From 79251f5ebe4cf9dd2f3e6aed590e09d756d39922 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Sun, 24 Nov 2013 21:41:57 +0800 Subject: [PATCH] ix: Import Intel ixgbe-2.5.15 MSI and legacy interrupt (line based interrupt) are working as of this commit. polling(4) will be supported and MSI-X will be brought back in the later commits. ixgbe is renamed to ix, which is consistent w/ the interface name, and this makes 'ifconfig ix0' work as expected. Local changes: - Reorganize RX and TX ring data structure; nuke useless 'queue'. - Rework RX and TX ring creation, destroy, initialization and cleanup. - Reorganize interrupt related data structure. This also prepares for bringing MSI-X back. - Rework interrupt allocation. - Rework MSI and legacy interrupt handler. - Enable RSS (2 RX rings) even if MSI or legacy interrupt is used. - Apply DragonFly specific RSS configuration. - Partially rework RX code path. - Enable TX header write-back. - Rework TX code path and TX watchdog mechanism. - Rework busdma(9) related bits. - Rework ifnet.if_ioctl method. - Reorganize initialize and stop code. - Reorganize attach and detach code. - Code clean up. --- share/man/man4/Makefile | 6 +- share/man/man4/{ixgbe.4 => ix.4} | 64 +- sys/conf/files | 21 +- sys/conf/options | 3 + sys/config/GENERIC | 2 +- sys/config/LINT | 2 +- sys/config/LINT64 | 2 +- sys/config/X86_64_GENERIC | 2 +- sys/dev/netif/Makefile | 2 +- sys/dev/netif/ix/Makefile | 17 + sys/dev/netif/ix/if_ix.c | 4511 ++++++++++++++++ sys/dev/netif/ix/if_ix.h | 320 ++ sys/dev/netif/{ixgbe => ix}/ixgbe_82598.c | 94 +- sys/dev/netif/{ixgbe => ix}/ixgbe_82598.h | 4 +- sys/dev/netif/{ixgbe => ix}/ixgbe_82599.c | 478 +- sys/dev/netif/{ixgbe => ix}/ixgbe_82599.h | 11 +- sys/dev/netif/{ixgbe => ix}/ixgbe_api.c | 128 +- sys/dev/netif/{ixgbe => ix}/ixgbe_api.h | 11 +- sys/dev/netif/{ixgbe => ix}/ixgbe_common.c | 642 ++- sys/dev/netif/{ixgbe => ix}/ixgbe_common.h | 29 +- sys/dev/netif/ix/ixgbe_dcb.c | 718 +++ sys/dev/netif/ix/ixgbe_dcb.h | 176 + sys/dev/netif/ix/ixgbe_dcb_82598.c | 359 ++ sys/dev/netif/ix/ixgbe_dcb_82598.h | 100 + sys/dev/netif/ix/ixgbe_dcb_82599.c | 586 ++ sys/dev/netif/ix/ixgbe_dcb_82599.h | 154 + sys/dev/netif/{ixgbe => ix}/ixgbe_mbx.c | 23 +- sys/dev/netif/{ixgbe => ix}/ixgbe_mbx.h | 16 +- sys/dev/netif/{ixgbe => ix}/ixgbe_osdep.h | 50 +- sys/dev/netif/{ixgbe => ix}/ixgbe_phy.c | 425 +- sys/dev/netif/{ixgbe => ix}/ixgbe_phy.h | 28 +- sys/dev/netif/{ixgbe => ix}/ixgbe_type.h | 146 +- sys/dev/netif/{ixgbe => ix}/ixgbe_vf.c | 187 +- sys/dev/netif/{ixgbe => ix}/ixgbe_vf.h | 13 +- sys/dev/netif/{ixgbe => ix}/ixgbe_x540.c | 95 +- sys/dev/netif/{ixgbe => ix}/ixgbe_x540.h | 8 +- sys/dev/netif/ixgbe/LICENSE | 33 - sys/dev/netif/ixgbe/Makefile | 22 - sys/dev/netif/ixgbe/README | 323 -- sys/dev/netif/ixgbe/ixgbe.c | 5697 -------------------- sys/dev/netif/ixgbe/ixgbe.h | 513 -- sys/dev/netif/ixgbe/ixgbe_defines.h | 44 - 42 files changed, 8798 insertions(+), 7267 deletions(-) rename share/man/man4/{ixgbe.4 => ix.4} (79%) create mode 100644 sys/dev/netif/ix/Makefile create mode 100644 sys/dev/netif/ix/if_ix.c create mode 100644 sys/dev/netif/ix/if_ix.h rename sys/dev/netif/{ixgbe => ix}/ixgbe_82598.c (94%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_82598.h (95%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_82599.c (85%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_82599.h (90%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_api.c (94%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_api.h (96%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_common.c (88%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_common.h (86%) create mode 100644 sys/dev/netif/ix/ixgbe_dcb.c create mode 100644 sys/dev/netif/ix/ixgbe_dcb.h create mode 100644 sys/dev/netif/ix/ixgbe_dcb_82598.c create mode 100644 sys/dev/netif/ix/ixgbe_dcb_82598.h create mode 100644 sys/dev/netif/ix/ixgbe_dcb_82599.c create mode 100644 sys/dev/netif/ix/ixgbe_dcb_82599.h rename sys/dev/netif/{ixgbe => ix}/ixgbe_mbx.c (97%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_mbx.h (90%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_osdep.h (84%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_phy.c (85%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_phy.h (85%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_type.h (95%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_vf.c (79%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_vf.h (92%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_x540.c (92%) rename sys/dev/netif/{ixgbe => ix}/ixgbe_x540.h (94%) delete mode 100644 sys/dev/netif/ixgbe/LICENSE delete mode 100644 sys/dev/netif/ixgbe/Makefile delete mode 100644 sys/dev/netif/ixgbe/README delete mode 100644 sys/dev/netif/ixgbe/ixgbe.c delete mode 100644 sys/dev/netif/ixgbe/ixgbe.h delete mode 100644 sys/dev/netif/ixgbe/ixgbe_defines.h diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 9c8654a3b7..f9a0c47232 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -140,7 +140,7 @@ MAN= aac.4 \ iwifw.4 \ iwn.4 \ iwnfw.4 \ - ixgbe.4 \ + ix.4 \ jme.4 \ joy.4 \ kate.4 \ @@ -447,7 +447,9 @@ MLINKS+=igb.4 if_igb.4 MLINKS+=iwi.4 if_iwi.4 #MLINKS+=iwl.4 if_iwl.4 MLINKS+=iwn.4 if_iwn.4 -MLINKS+=ixgbe.4 if_ixgbe.4 +MLINKS+=ix.4 if_ix.4 \ + ix.4 ixgbe.4 \ + ix.4 if_ixgbe.4 MLINKS+=jme.4 if_jme.4 MLINKS+=kue.4 if_kue.4 MLINKS+=lge.4 if_lge.4 diff --git a/share/man/man4/ixgbe.4 b/share/man/man4/ix.4 similarity index 79% rename from share/man/man4/ixgbe.4 rename to share/man/man4/ix.4 index bc8ca0a19c..c13fa02fc5 100644 --- a/share/man/man4/ixgbe.4 +++ b/share/man/man4/ix.4 @@ -31,31 +31,35 @@ .\" .\" $FreeBSD: src/share/man/man4/ixgbe.4,v 1.2 2008/06/17 21:14:02 brueffer Exp $ .\" -.Dd June 30, 2012 -.Dt IXGBE 4 +.Dd December 30, 2013 +.Dt IX 4 .Os .Sh NAME -.Nm ixgbe -.Nd "Intel(R) 10Gb Ethernet driver for the DragonFly BSD operating system" +.Nm ix +.Nd "Intel(R) 10Gb Ethernet driver" .Sh SYNOPSIS To compile this driver into the kernel, place the following line in your kernel configuration file: .Bd -ragged -offset indent -.Cd "device ixgbe" +.Cd "device ix" .Ed .Pp Alternatively, to load the driver as a module at boot time, place the following line in .Xr loader.conf 5 : .Bd -literal -offset indent -if_ixgbe_load="YES" +if_ix_load="YES" .Ed .Sh DESCRIPTION The .Nm driver provides support for PCI 10Gb Ethernet adapters based on -the Intel 82598EB Intel(R) Network Connections. +the Intel +82598EB, +82599 and +X540 +Intel(R) Network Connections. The driver supports Jumbo Frames, MSIX, TSO, and RSS. .Pp For questions related to hardware requirements, @@ -79,22 +83,44 @@ driver supports the following cards: .Pp .Bl -bullet -compact .It -Intel(R) 10 Gigabit XF SR/AF Dual Port Server Adapter +Intel 10 Gigabit AF DA Dual Port Server Adapter .It -Intel(R) 10 Gigabit XF SR/LR Server Adapter +Intel 10 Gigabit AT Server Adapter .It -Intel(R) 82598EB 10 Gigabit AF Network Connection +Intel 10 Gigabit AT2 Server Adapter .It -Intel(R) 82598EB 10 Gigabit AT CX4 Network Connection +Intel 10 Gigabit CX4 Dual Port Server Adapter +.It +Intel 10 Gigabit XF LR Server Adapter +.It +Intel 10 Gigabit XF SR Dual Port Server Adapter +.It +Intel 10 Gigabit XF SR Server Adapter +.It +Intel 82598 10 Gigabit Ethernet Controller +.It +Intel 82599 10 Gigabit Ethernet Controller +.It +Intel Ethernet Controller X540-AT2 +.It +Intel Ethernet Converged Network Adapter X520 Series +.It +Intel Ethernet Converged Network Adapter X540-T1 +.It +Intel Ethernet Converged Network Adapter X540-T2 +.It +Intel Ethernet Server Adapter X520 Series +.It +Intel Ethernet Server Adapter X520-DA2 +.It +Intel Ethernet Server Adapter X520-LR1 +.It +Intel Ethernet Server Adapter X520-SR1 +.It +Intel Ethernet Server Adapter X520-SR2 +.It +Intel Ethernet Server Adapter X520-T2 .El -.Sh PERFORMANCE -The default -.Dx -configuration may not give the best possible -performance with single streams TCP connections. -Increasing the value of the -.Va net.inet.tcp.sosend_agglim -sysctl to 12 or more will increase sending speeds. .Sh DIAGNOSTICS .Bl -diag .It "ix%d: Unable to allocate bus resource: memory" diff --git a/sys/conf/files b/sys/conf/files index d9e09505e7..9bbffa3b55 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -298,15 +298,18 @@ dev/netif/ep/if_ep_pccard.c optional ep pccard dev/netif/em/if_em.c optional em dev/netif/emx/if_emx.c optional emx dev/netif/igb/if_igb.c optional igb -dev/netif/ixgbe/ixgbe.c optional ixgbe -dev/netif/ixgbe/ixgbe_82598.c optional ixgbe -dev/netif/ixgbe/ixgbe_82599.c optional ixgbe -dev/netif/ixgbe/ixgbe_api.c optional ixgbe -dev/netif/ixgbe/ixgbe_common.c optional ixgbe -dev/netif/ixgbe/ixgbe_mbx.c optional ixgbe -dev/netif/ixgbe/ixgbe_phy.c optional ixgbe -dev/netif/ixgbe/ixgbe_vf.c optional ixgbe -dev/netif/ixgbe/ixgbe_x540.c optional ixgbe +dev/netif/ix/if_ix.c optional ix +dev/netif/ix/ixgbe_82598.c optional ix +dev/netif/ix/ixgbe_82599.c optional ix +dev/netif/ix/ixgbe_api.c optional ix +dev/netif/ix/ixgbe_common.c optional ix +dev/netif/ix/ixgbe_dcb.c optional ix +dev/netif/ix/ixgbe_dcb_82598.c optional ix +dev/netif/ix/ixgbe_dcb_82599.c optional ix +dev/netif/ix/ixgbe_mbx.c optional ix +dev/netif/ix/ixgbe_phy.c optional ix +dev/netif/ix/ixgbe_vf.c optional ix +dev/netif/ix/ixgbe_x540.c optional ix dev/netif/ig_hal/e1000_80003es2lan.c optional ig_hal dev/netif/ig_hal/e1000_82540.c optional ig_hal dev/netif/ig_hal/e1000_82541.c optional ig_hal diff --git a/sys/conf/options b/sys/conf/options index 11675a5003..3d72312ea9 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -636,6 +636,9 @@ IGB_RSS_DEBUG opt_igb.h IGB_TSS_DEBUG opt_igb.h IGB_MSIX_DEBUG opt_igb.h +# ix driver +IX_RSS_DEBUG opt_ix.h + # Options for the Intel 802.11n wireless driver IWN_DEBUG opt_iwn.h diff --git a/sys/config/GENERIC b/sys/config/GENERIC index 097973dc2b..cc168b9c1b 100644 --- a/sys/config/GENERIC +++ b/sys/config/GENERIC @@ -232,7 +232,7 @@ device em # Intel PRO/1000 adapter Gigabit Ethernet Card (``Wiseman'') device igb # Intel Pro/1000 (82575, 82576, 82580, i350) # Requires ig_hal device ig_hal # Intel PRO/1000 hardware abstraction layer -device ixgbe # Intel PRO/10GbE PCIE Ethernet Family +device ix # Intel PRO/10GbE PCIE Ethernet Family device oce # Emulex OneConnect 10Gb diff --git a/sys/config/LINT b/sys/config/LINT index 431ebc4824..dd145f1707 100644 --- a/sys/config/LINT +++ b/sys/config/LINT @@ -1778,7 +1778,7 @@ device emx # Intel Pro/1000 (8257{1,2,3,4}) device igb # Intel Pro/1000 (82575, 82576, 82580, i350) # Requires ig_hal device ig_hal # Intel Pro/1000 hardware abstraction layer -device ixgbe # Intel PRO/10GbE PCIE Ethernet Family +device ix # Intel PRO/10GbE PCIE Ethernet Family device et # Agere ET1310 10/100/1000 Ethernet device lge # Level 1 LXT1001 (``Mercury'') device mxge # Myricom Myri-10G 10GbE NIC diff --git a/sys/config/LINT64 b/sys/config/LINT64 index 650f3f1955..5a8125eaf8 100644 --- a/sys/config/LINT64 +++ b/sys/config/LINT64 @@ -1624,7 +1624,7 @@ device emx # Intel Pro/1000 (8257{1,2,3,4}) device igb # Intel Pro/1000 (82575, 82576, 82580, i350) # Requires ig_hal device ig_hal # Intel Pro/1000 hardware abstraction layer -device ixgbe # Intel PRO/10GbE PCIE Ethernet Family +device ix # Intel PRO/10GbE PCIE Ethernet Family device et # Agere ET1310 10/100/1000 Ethernet device lge # Level 1 LXT1001 (``Mercury'') device mxge # Myricom Myri-10G 10GbE NIC diff --git a/sys/config/X86_64_GENERIC b/sys/config/X86_64_GENERIC index 3fc5b6c275..db99db9980 100644 --- a/sys/config/X86_64_GENERIC +++ b/sys/config/X86_64_GENERIC @@ -211,7 +211,7 @@ device em # Intel PRO/1000 adapter Gigabit Ethernet Card (``Wiseman'') device igb # Intel Pro/1000 (82575, 82576, 82580, i350) # Requires ig_hal device ig_hal # Intel PRO/1000 hardware abstraction layer -device ixgbe # Intel PRO/10GbE PCIE Ethernet Family +device ix # Intel PRO/10GbE PCIE Ethernet Family device oce # Emulex OneConnect 10Gb diff --git a/sys/dev/netif/Makefile b/sys/dev/netif/Makefile index 25485a7418..843420e7e2 100644 --- a/sys/dev/netif/Makefile +++ b/sys/dev/netif/Makefile @@ -3,7 +3,7 @@ SUBDIR= an age alc ale ath bce bfe bge \ fwe fxp ic iwi iwn jme lge lnc \ mii_layer my msk mxge ndis nfe nge oce pcn \ ral re rl sbsh sf sis sk sln sr ste stge ti tl tx txp \ - vge vr vx wb wi wpi xe xl ig_hal emx ae igb ixgbe bnx + vge vr vx wb wi wpi xe xl ig_hal emx ae igb ix bnx .if ${MACHINE_ARCH} == "i386" SUBDIR+=ar sbni diff --git a/sys/dev/netif/ix/Makefile b/sys/dev/netif/ix/Makefile new file mode 100644 index 0000000000..a7638b473c --- /dev/null +++ b/sys/dev/netif/ix/Makefile @@ -0,0 +1,17 @@ +KMOD = if_ix +SRCS = if_ix.c +SRCS += device_if.h bus_if.h pci_if.h +SRCS += opt_ix.h + +SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c ixgbe_vf.c ixgbe_mbx.c +SRCS += ixgbe_dcb.c ixgbe_dcb_82598.c ixgbe_dcb_82599.c +SRCS += ixgbe_82598.c ixgbe_82599.c ixgbe_x540.c + +.ifndef BUILDING_WITH_KERNEL + +opt_ix.h: + touch ${.OBJDIR}/${.TARGET} + +.endif + +.include diff --git a/sys/dev/netif/ix/if_ix.c b/sys/dev/netif/ix/if_ix.c new file mode 100644 index 0000000000..e0878fdf87 --- /dev/null +++ b/sys/dev/netif/ix/if_ix.c @@ -0,0 +1,4511 @@ +/* + * Copyright (c) 2001-2013, 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. + */ + +#include "opt_ix.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#ifdef IX_RSS_DEBUG +#define IX_RSS_DPRINTF(sc, lvl, fmt, ...) \ +do { \ + if (sc->rss_debug >= lvl) \ + if_printf(&sc->arpcom.ac_if, fmt, __VA_ARGS__); \ +} while (0) +#else /* !IX_RSS_DEBUG */ +#define IX_RSS_DPRINTF(sc, lvl, fmt, ...) ((void)0) +#endif /* IX_RSS_DEBUG */ + +#define IX_NAME "Intel(R) PRO/10GbE " +#define IX_DEVICE(id) \ + { IXGBE_VENDOR_ID, IXGBE_DEV_ID_##id, IX_NAME #id } +#define IX_DEVICE_NULL { 0, 0, NULL } + +static struct ix_device { + uint16_t vid; + uint16_t did; + const char *desc; +} ix_devices[] = { + IX_DEVICE(82598AF_DUAL_PORT), + IX_DEVICE(82598AF_SINGLE_PORT), + IX_DEVICE(82598EB_CX4), + IX_DEVICE(82598AT), + IX_DEVICE(82598AT2), + IX_DEVICE(82598), + IX_DEVICE(82598_DA_DUAL_PORT), + IX_DEVICE(82598_CX4_DUAL_PORT), + IX_DEVICE(82598EB_XF_LR), + IX_DEVICE(82598_SR_DUAL_PORT_EM), + IX_DEVICE(82598EB_SFP_LOM), + IX_DEVICE(82599_KX4), + IX_DEVICE(82599_KX4_MEZZ), + IX_DEVICE(82599_SFP), + IX_DEVICE(82599_XAUI_LOM), + IX_DEVICE(82599_CX4), + IX_DEVICE(82599_T3_LOM), + IX_DEVICE(82599_COMBO_BACKPLANE), + IX_DEVICE(82599_BACKPLANE_FCOE), + IX_DEVICE(82599_SFP_SF2), + IX_DEVICE(82599_SFP_FCOE), + IX_DEVICE(82599EN_SFP), + IX_DEVICE(82599_SFP_SF_QP), + IX_DEVICE(X540T), + + /* required last entry */ + IX_DEVICE_NULL +}; + +static int ix_probe(device_t); +static int ix_attach(device_t); +static int ix_detach(device_t); +static int ix_shutdown(device_t); + +static void ix_serialize(struct ifnet *, enum ifnet_serialize); +static void ix_deserialize(struct ifnet *, enum ifnet_serialize); +static int ix_tryserialize(struct ifnet *, enum ifnet_serialize); +#ifdef INVARIANTS +static void ix_serialize_assert(struct ifnet *, enum ifnet_serialize, + boolean_t); +#endif +static void ix_start(struct ifnet *, struct ifaltq_subque *); +static void ix_watchdog(struct ifaltq_subque *); +static int ix_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); +static void ix_init(void *); +static void ix_stop(struct ix_softc *); +static void ix_media_status(struct ifnet *, struct ifmediareq *); +static int ix_media_change(struct ifnet *); +static void ix_timer(void *); + +static void ix_add_sysctl(struct ix_softc *); +static int ix_sysctl_tx_wreg_nsegs(SYSCTL_HANDLER_ARGS); +static int ix_sysctl_rx_wreg_nsegs(SYSCTL_HANDLER_ARGS); +static int ix_sysctl_txd(SYSCTL_HANDLER_ARGS); +static int ix_sysctl_rxd(SYSCTL_HANDLER_ARGS); +static int ix_sysctl_tx_intr_nsegs(SYSCTL_HANDLER_ARGS); +static int ix_sysctl_intr_rate(SYSCTL_HANDLER_ARGS); +static int ix_sysctl_flowctrl(SYSCTL_HANDLER_ARGS); +#ifdef foo +static int ix_sysctl_advspeed(SYSCTL_HANDLER_ARGS); +#endif +#if 0 +static void ix_add_hw_stats(struct ix_softc *); +#endif + +static void ix_slot_info(struct ix_softc *); +static int ix_alloc_rings(struct ix_softc *); +static void ix_free_rings(struct ix_softc *); +static void ix_setup_ifp(struct ix_softc *); +static void ix_setup_serialize(struct ix_softc *); +static void ix_set_ring_inuse(struct ix_softc *, boolean_t); +static void ix_set_timer_cpuid(struct ix_softc *, boolean_t); +static void ix_update_stats(struct ix_softc *); + +static void ix_set_promisc(struct ix_softc *); +static void ix_set_multi(struct ix_softc *); +static void ix_set_vlan(struct ix_softc *); +static uint8_t *ix_mc_array_itr(struct ixgbe_hw *, uint8_t **, uint32_t *); + +static int ix_get_txring_inuse(const struct ix_softc *, boolean_t); +static void ix_init_tx_ring(struct ix_tx_ring *); +static void ix_free_tx_ring(struct ix_tx_ring *); +static int ix_create_tx_ring(struct ix_tx_ring *); +static void ix_destroy_tx_ring(struct ix_tx_ring *, int); +static void ix_init_tx_unit(struct ix_softc *); +static int ix_encap(struct ix_tx_ring *, struct mbuf **, + uint16_t *, int *); +static int ix_tx_ctx_setup(struct ix_tx_ring *, + const struct mbuf *, uint32_t *, uint32_t *); +static int ix_tso_ctx_setup(struct ix_tx_ring *, + const struct mbuf *, uint32_t *, uint32_t *); +static void ix_txeof(struct ix_tx_ring *); + +static int ix_get_rxring_inuse(const struct ix_softc *, boolean_t); +static int ix_init_rx_ring(struct ix_rx_ring *); +static void ix_free_rx_ring(struct ix_rx_ring *); +static int ix_create_rx_ring(struct ix_rx_ring *); +static void ix_destroy_rx_ring(struct ix_rx_ring *, int); +static void ix_init_rx_unit(struct ix_softc *); +#if 0 +static void ix_setup_hw_rsc(struct ix_rx_ring *); +#endif +static int ix_newbuf(struct ix_rx_ring *, int, boolean_t); +static void ix_rxeof(struct ix_rx_ring *); +static void ix_rx_discard(struct ix_rx_ring *, int, boolean_t); +static void ix_enable_rx_drop(struct ix_softc *); +static void ix_disable_rx_drop(struct ix_softc *); + +static int ix_alloc_intr(struct ix_softc *); +static void ix_free_intr(struct ix_softc *); +static int ix_setup_intr(struct ix_softc *); +static void ix_teardown_intr(struct ix_softc *, int); +static void ix_enable_intr(struct ix_softc *); +static void ix_disable_intr(struct ix_softc *); +static void ix_set_ivar(struct ix_softc *, uint8_t, uint8_t, int8_t); +#if 0 +static void ix_configure_ivars(struct ix_softc *); +#endif +static void ix_set_eitr(struct ix_softc *, int, int); +static void ix_intr(void *); + +static void ix_config_link(struct ix_softc *); +static boolean_t ix_sfp_probe(struct ix_softc *); +static boolean_t ix_is_sfp(const struct ixgbe_hw *); +static void ix_setup_optics(struct ix_softc *); +static void ix_update_link_status(struct ix_softc *); +static void ix_handle_link(struct ix_softc *); +static void ix_handle_mod(struct ix_softc *); +static void ix_handle_msf(struct ix_softc *); + +#if 0 +static void ix_msix_que(void *); +static void ix_msix_link(void *); +static int ix_allocate_msix(struct ix_softc *); +static int ix_setup_msix(struct ix_softc *); +static void ix_handle_que(void *, int); +#endif + +/* XXX Shared code structure requires this for the moment */ +extern void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *); + +static device_method_t ix_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ix_probe), + DEVMETHOD(device_attach, ix_attach), + DEVMETHOD(device_detach, ix_detach), + DEVMETHOD(device_shutdown, ix_shutdown), + DEVMETHOD_END +}; + +static driver_t ix_driver = { + "ix", + ix_methods, + sizeof(struct ix_softc) +}; + +static devclass_t ix_devclass; + +DECLARE_DUMMY_MODULE(if_ix); +DRIVER_MODULE(if_ix, pci, ix_driver, ix_devclass, NULL, NULL); + +static int ix_msi_enable = 1; +static int ix_rxr = 0; +static int ix_txd = IX_PERF_TXD; +static int ix_rxd = IX_PERF_RXD; +static int ix_unsupported_sfp = 0; + +TUNABLE_INT("hw.ix.msi.enable", &ix_msi_enable); +TUNABLE_INT("hw.ix.rxr", &ix_rxr); +TUNABLE_INT("hw.ix.txd", &ix_txd); +TUNABLE_INT("hw.ix.rxd", &ix_rxd); +TUNABLE_INT("hw.ix.unsupported_sfp", &ix_unsupported_sfp); + +/* + * Smart speed setting, default to on. This only works + * as a compile option right now as its during attach, + * set this to 'ixgbe_smart_speed_off' to disable. + */ +static const enum ixgbe_smart_speed ix_smart_speed = + ixgbe_smart_speed_on; + +static int +ix_probe(device_t dev) +{ + const struct ix_device *d; + uint16_t vid, did; + + vid = pci_get_vendor(dev); + did = pci_get_device(dev); + + for (d = ix_devices; d->desc != NULL; ++d) { + if (vid == d->vid && did == d->did) { + device_set_desc(dev, d->desc); + return 0; + } + } + return ENXIO; +} + +static int +ix_attach(device_t dev) +{ + struct ix_softc *sc = device_get_softc(dev); + struct ixgbe_hw *hw; + int error; + uint16_t csum; + uint32_t ctrl_ext; + + sc->dev = sc->osdep.dev = dev; + hw = &sc->hw; + + if_initname(&sc->arpcom.ac_if, device_get_name(dev), + device_get_unit(dev)); + ifmedia_init(&sc->media, IFM_IMASK, + ix_media_change, ix_media_status); + + /* Save frame size */ + sc->max_frame_size = ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN; + + callout_init_mp(&sc->timer); + lwkt_serialize_init(&sc->main_serialize); + + /* + * Save off the information about this board + */ + hw->vendor_id = pci_get_vendor(dev); + hw->device_id = pci_get_device(dev); + hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); + hw->subsystem_vendor_id = pci_read_config(dev, PCIR_SUBVEND_0, 2); + hw->subsystem_device_id = pci_read_config(dev, PCIR_SUBDEV_0, 2); + + ixgbe_set_mac_type(hw); + + /* Pick up the 82599 and VF settings */ + if (hw->mac.type != ixgbe_mac_82598EB) + hw->phy.smart_speed = ix_smart_speed; + + /* Enable bus mastering */ + pci_enable_busmaster(dev); + + /* + * Allocate IO memory + */ + sc->mem_rid = PCIR_BAR(0); + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->mem_rid, RF_ACTIVE); + if (sc->mem_res == NULL) { + device_printf(dev, "Unable to allocate bus resource: memory\n"); + error = ENXIO; + goto failed; + } + + sc->osdep.mem_bus_space_tag = rman_get_bustag(sc->mem_res); + sc->osdep.mem_bus_space_handle = rman_get_bushandle(sc->mem_res); + + sc->hw.hw_addr = (uint8_t *)&sc->osdep.mem_bus_space_handle; + sc->hw.back = &sc->osdep; + + /* + * Configure total supported RX/TX ring count + */ + sc->rx_ring_cnt = device_getenv_int(dev, "rxr", ix_rxr); + sc->rx_ring_cnt = if_ring_count2(sc->rx_ring_cnt, IX_MAX_RXRING); + sc->rx_ring_inuse = sc->rx_ring_cnt; + + sc->tx_ring_cnt = 1; + sc->tx_ring_inuse = sc->tx_ring_cnt; + + /* Allocate TX/RX rings */ + error = ix_alloc_rings(sc); + if (error) + goto failed; + + /* Allocate interrupt */ + error = ix_alloc_intr(sc); + if (error) + goto failed; + + /* Setup serializes */ + ix_setup_serialize(sc); + + /* Allocate multicast array memory. */ + sc->mta = kmalloc(IXGBE_ETH_LENGTH_OF_ADDRESS * IX_MAX_MCASTADDR, + M_DEVBUF, M_WAITOK); + + /* Initialize the shared code */ + hw->allow_unsupported_sfp = ix_unsupported_sfp; + error = ixgbe_init_shared_code(hw); + if (error == IXGBE_ERR_SFP_NOT_PRESENT) { + /* + * No optics in this port; ask timer routine + * to probe for later insertion. + */ + sc->sfp_probe = TRUE; + error = 0; + } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { + device_printf(dev, "Unsupported SFP+ module detected!\n"); + error = EIO; + goto failed; + } else if (error) { + device_printf(dev, "Unable to initialize the shared code\n"); + error = EIO; + goto failed; + } + + /* Make sure we have a good EEPROM before we read from it */ + if (ixgbe_validate_eeprom_checksum(&sc->hw, &csum) < 0) { + device_printf(dev, "The EEPROM Checksum Is Not Valid\n"); + error = EIO; + goto failed; + } + + error = ixgbe_init_hw(hw); + if (error == IXGBE_ERR_EEPROM_VERSION) { + device_printf(dev, "Pre-production device detected\n"); + } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { + device_printf(dev, "Unsupported SFP+ Module\n"); + error = EIO; + goto failed; + } else if (error == IXGBE_ERR_SFP_NOT_PRESENT) { + device_printf(dev, "No SFP+ Module found\n"); + } + + /* Detect and set physical type */ + ix_setup_optics(sc); + + /* Setup OS specific network interface */ + ix_setup_ifp(sc); + + /* Add sysctl tree */ + ix_add_sysctl(sc); + + error = ix_setup_intr(sc); + if (error) { + ether_ifdetach(&sc->arpcom.ac_if); + goto failed; + } + + /* Initialize statistics */ + ix_update_stats(sc); + + /* + * Check PCIE slot type/speed/width + */ + ix_slot_info(sc); + + /* Set an initial default flow control value */ + sc->fc = ixgbe_fc_full; + + /* Let hardware know driver is loaded */ + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + + return 0; +failed: + ix_detach(dev); + return error; +} + +static int +ix_detach(device_t dev) +{ + struct ix_softc *sc = device_get_softc(dev); + + if (device_is_attached(dev)) { + struct ifnet *ifp = &sc->arpcom.ac_if; + uint32_t ctrl_ext; + + ifnet_serialize_all(ifp); + + ix_stop(sc); + ix_teardown_intr(sc, sc->intr_cnt); + + ifnet_deserialize_all(ifp); + + callout_terminate(&sc->timer); + ether_ifdetach(ifp); + + /* 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); + } + + ifmedia_removeall(&sc->media); + bus_generic_detach(dev); + + if (sc->sysctl_tree != NULL) + sysctl_ctx_free(&sc->sysctl_ctx); + + ix_free_intr(sc); + + if (sc->mem_res != NULL) { + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, + sc->mem_res); + } + + ix_free_rings(sc); + + if (sc->mta != NULL) + kfree(sc->mta, M_DEVBUF); + if (sc->serializes != NULL) + kfree(sc->serializes, M_DEVBUF); + + return 0; +} + +static int +ix_shutdown(device_t dev) +{ + struct ix_softc *sc = device_get_softc(dev); + struct ifnet *ifp = &sc->arpcom.ac_if; + + ifnet_serialize_all(ifp); + ix_stop(sc); + ifnet_deserialize_all(ifp); + + return 0; +} + +static void +ix_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) +{ + struct ix_softc *sc = ifp->if_softc; + struct ix_tx_ring *txr = ifsq_get_priv(ifsq); + int idx = -1; + uint16_t nsegs; + + KKASSERT(txr->tx_ifsq == ifsq); + ASSERT_SERIALIZED(&txr->tx_serialize); + + if ((ifp->if_flags & IFF_RUNNING) == 0 || ifsq_is_oactive(ifsq)) + return; + + if (!sc->link_active) { + ifsq_purge(ifsq); + return; + } + + while (!ifsq_is_empty(ifsq)) { + struct mbuf *m_head; + + if (txr->tx_avail <= IX_MAX_SCATTER + IX_TX_RESERVED) { + ifsq_set_oactive(ifsq); + txr->tx_watchdog.wd_timer = 5; + break; + } + + m_head = ifsq_dequeue(ifsq); + if (m_head == NULL) + break; + + if (ix_encap(txr, &m_head, &nsegs, &idx)) { + IFNET_STAT_INC(ifp, oerrors, 1); + continue; + } + + if (nsegs >= txr->tx_wreg_nsegs) { + IXGBE_WRITE_REG(&sc->hw, IXGBE_TDT(txr->tx_idx), idx); + nsegs = 0; + idx = -1; + } + + ETHER_BPF_MTAP(ifp, m_head); + } + if (idx >= 0) + IXGBE_WRITE_REG(&sc->hw, IXGBE_TDT(txr->tx_idx), idx); +} + +static int +ix_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) +{ + struct ix_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + int error = 0, mask, reinit; + + ASSERT_IFNET_SERIALIZED_ALL(ifp); + + switch (command) { + case SIOCSIFMTU: + if (ifr->ifr_mtu > IX_MAX_FRAME_SIZE - ETHER_HDR_LEN) { + error = EINVAL; + } else { + ifp->if_mtu = ifr->ifr_mtu; + sc->max_frame_size = + ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; + ix_init(sc); + } + break; + + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING) { + if ((ifp->if_flags ^ sc->if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) + ix_set_promisc(sc); + } else { + ix_init(sc); + } + } else if (ifp->if_flags & IFF_RUNNING) { + ix_stop(sc); + } + sc->if_flags = ifp->if_flags; + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (ifp->if_flags & IFF_RUNNING) { + ix_disable_intr(sc); + ix_set_multi(sc); + ix_enable_intr(sc); + } + break; + + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->media, command); + break; + + case SIOCSIFCAP: + reinit = 0; + mask = ifr->ifr_reqcap ^ ifp->if_capenable; + if (mask & IFCAP_RXCSUM) { + ifp->if_capenable ^= IFCAP_RXCSUM; + reinit = 1; + } + if (mask & IFCAP_VLAN_HWTAGGING) { + ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + reinit = 1; + } + if (mask & IFCAP_TXCSUM) { + ifp->if_capenable ^= IFCAP_TXCSUM; + if (ifp->if_capenable & IFCAP_TXCSUM) + ifp->if_hwassist |= CSUM_OFFLOAD; + else + ifp->if_hwassist &= ~CSUM_OFFLOAD; + } + if (mask & IFCAP_TSO) { + ifp->if_capenable ^= IFCAP_TSO; + if (ifp->if_capenable & IFCAP_TSO) + ifp->if_hwassist |= CSUM_TSO; + else + ifp->if_hwassist &= ~CSUM_TSO; + } + if (mask & IFCAP_RSS) + ifp->if_capenable ^= IFCAP_RSS; + if (reinit && (ifp->if_flags & IFF_RUNNING)) + ix_init(sc); + break; + +#if 0 + case SIOCGI2C: + { + struct ixgbe_i2c_req i2c; + error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); + if (error) + break; + if ((i2c.dev_addr != 0xA0) || (i2c.dev_addr != 0xA2)){ + error = EINVAL; + break; + } + hw->phy.ops.read_i2c_byte(hw, i2c.offset, + i2c.dev_addr, i2c.data); + error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); + break; + } +#endif + + default: + error = ether_ioctl(ifp, command, data); + break; + } + return error; +} + +#define IXGBE_MHADD_MFS_SHIFT 16 + +static void +ix_init(void *xsc) +{ + struct ix_softc *sc = xsc; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ixgbe_hw *hw = &sc->hw; + uint32_t rxpb, frame, size, tmp; + uint32_t gpie, rxctrl; + int i, error; + + ASSERT_IFNET_SERIALIZED_ALL(ifp); + + ix_stop(sc); + + /* Configure # of used RX/TX rings */ + ix_set_ring_inuse(sc, FALSE); + ifq_set_subq_mask(&ifp->if_snd, sc->tx_ring_inuse - 1); + + /* Get the latest mac address, User can use a LAA */ + bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); + ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1); + hw->addr_ctrl.rar_used_count = 1; + + /* Prepare transmit descriptors and buffers */ + for (i = 0; i < sc->tx_ring_inuse; ++i) + ix_init_tx_ring(&sc->tx_rings[i]); + + ixgbe_init_hw(hw); + ix_init_tx_unit(sc); + + /* Setup Multicast table */ + ix_set_multi(sc); + + /* Prepare receive descriptors and buffers */ + for (i = 0; i < sc->rx_ring_inuse; ++i) { + error = ix_init_rx_ring(&sc->rx_rings[i]); + if (error) { + if_printf(ifp, "Could not initialize RX ring%d\n", i); + ix_stop(sc); + return; + } + } + + /* Configure RX settings */ + ix_init_rx_unit(sc); + + gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); + + /* Enable Fan Failure Interrupt */ + gpie |= IXGBE_SDP1_GPIEN; + + /* Add for Module detection */ + if (hw->mac.type == ixgbe_mac_82599EB) + gpie |= IXGBE_SDP2_GPIEN; + + /* Thermal Failure Detection */ + if (hw->mac.type == ixgbe_mac_X540) + gpie |= IXGBE_SDP0_GPIEN; + + if (sc->intr_type == PCI_INTR_TYPE_MSIX) { + /* Enable Enhanced MSIX mode */ + gpie |= IXGBE_GPIE_MSIX_MODE; + gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | + IXGBE_GPIE_OCD; + } + IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); + + /* Set MTU size */ + if (ifp->if_mtu > ETHERMTU) { + uint32_t mhadd; + + mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); + mhadd &= ~IXGBE_MHADD_MFS_MASK; + mhadd |= sc->max_frame_size << IXGBE_MHADD_MFS_SHIFT; + IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); + } + + /* + * Enable TX rings + */ + for (i = 0; i < sc->tx_ring_inuse; ++i) { + uint32_t txdctl; + + txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); + txdctl |= IXGBE_TXDCTL_ENABLE; + + /* + * Set WTHRESH to 0, since TX head write-back is used + */ + txdctl &= ~(0x7f << 16); + + /* + * When the internal queue falls below PTHRESH (32), + * start prefetching as long as there are at least + * HTHRESH (1) buffers ready. The values are taken + * from the Intel linux driver 3.8.21. + * Prefetching enables tx line rate even with 1 queue. + */ + txdctl |= (32 << 0) | (1 << 8); + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), txdctl); + } + + /* + * Enable RX rings + */ + for (i = 0; i < sc->rx_ring_inuse; ++i) { + uint32_t rxdctl; + int k; + + rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); + if (hw->mac.type == ixgbe_mac_82598EB) { + /* + * PTHRESH = 21 + * HTHRESH = 4 + * WTHRESH = 8 + */ + rxdctl &= ~0x3FFFFF; + rxdctl |= 0x080420; + } + rxdctl |= IXGBE_RXDCTL_ENABLE; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl); + for (k = 0; k < 10; ++k) { + if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)) & + IXGBE_RXDCTL_ENABLE) + break; + else + msec_delay(1); + } + wmb(); + IXGBE_WRITE_REG(hw, IXGBE_RDT(i), + sc->rx_rings[0].rx_ndesc - 1); + } + + /* Set up VLAN support and filter */ + ix_set_vlan(sc); + + /* Enable Receive engine */ + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + if (hw->mac.type == ixgbe_mac_82598EB) + rxctrl |= IXGBE_RXCTRL_DMBYPS; + rxctrl |= IXGBE_RXCTRL_RXEN; + ixgbe_enable_rx_dma(hw, rxctrl); + + if (sc->intr_type == PCI_INTR_TYPE_MSIX) { +#if 0 + ix_configure_ivars(sc); +#endif + /* Set up auto-mask */ + if (hw->mac.type == ixgbe_mac_82598EB) + IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); + else { + IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); + IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); + } + } else { + for (i = 0; i < sc->tx_ring_inuse; ++i) + ix_set_ivar(sc, i, sc->tx_rings[i].tx_intr_vec, 1); + for (i = 0; i < sc->rx_ring_inuse; ++i) + ix_set_ivar(sc, i, sc->rx_rings[i].rx_intr_vec, 0); + IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); + ix_set_eitr(sc, 0, sc->intr_data[0].intr_rate); + } + + /* + * Check on any SFP devices that need to be kick-started + */ + if (hw->phy.type == ixgbe_phy_none) { + error = hw->phy.ops.identify(hw); + if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { + if_printf(ifp, + "Unsupported SFP+ module type was detected.\n"); + /* XXX stop */ + return; + } + } + +#if 0 + /* Set moderation on the Link interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EITR(sc->linkvec), IXGBE_LINK_ITR); +#endif + + /* Config/Enable Link */ + ix_config_link(sc); + + /* + * Hardware Packet Buffer & Flow Control setup + */ + frame = sc->max_frame_size; + + /* Calculate High Water */ + if (hw->mac.type == ixgbe_mac_X540) + tmp = IXGBE_DV_X540(frame, frame); + else + tmp = IXGBE_DV(frame, frame); + size = IXGBE_BT2KB(tmp); + rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; + hw->fc.high_water[0] = rxpb - size; + + /* Now calculate Low Water */ + if (hw->mac.type == ixgbe_mac_X540) + tmp = IXGBE_LOW_DV_X540(frame); + else + tmp = IXGBE_LOW_DV(frame); + hw->fc.low_water[0] = IXGBE_BT2KB(tmp); + + hw->fc.requested_mode = sc->fc; + hw->fc.pause_time = IX_FC_PAUSE; + hw->fc.send_xon = TRUE; + + /* Initialize the FC settings */ + ixgbe_start_hw(hw); + + /* And now turn on interrupts */ + ix_enable_intr(sc); + + ifp->if_flags |= IFF_RUNNING; + for (i = 0; i < sc->tx_ring_inuse; ++i) { + ifsq_clr_oactive(sc->tx_rings[i].tx_ifsq); + ifsq_watchdog_start(&sc->tx_rings[i].tx_watchdog); + } + + ix_set_timer_cpuid(sc, FALSE); + callout_reset_bycpu(&sc->timer, hz, ix_timer, sc, sc->timer_cpuid); +} + +#if 0 +/* +** +** MSIX Interrupt Handlers and Tasklets +** +*/ + +static __inline void +ix_enable_queue(struct ix_softc *sc, uint32_t vector) +{ + struct ixgbe_hw *hw = &sc->hw; + uint64_t queue = (uint64_t)(1 << vector); + uint32_t mask; + + if (hw->mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & queue); + IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); + } else { + mask = (queue & 0xFFFFFFFF); + if (mask) + IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask); + mask = (queue >> 32); + if (mask) + IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask); + } +} + +static __inline void +ix_disable_queue(struct ix_softc *sc, uint32_t vector) +{ + struct ixgbe_hw *hw = &sc->hw; + uint64_t queue = (uint64_t)(1 << vector); + uint32_t mask; + + if (hw->mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & queue); + IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask); + } else { + mask = (queue & 0xFFFFFFFF); + if (mask) + IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); + mask = (queue >> 32); + if (mask) + IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); + } +} + +static __inline void +ix_rearm_queues(struct ix_softc *sc, uint64_t queues) +{ + uint32_t mask; + + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + mask = (IXGBE_EIMS_RTX_QUEUE & queues); + IXGBE_WRITE_REG(&sc->hw, IXGBE_EICS, mask); + } else { + mask = (queues & 0xFFFFFFFF); + IXGBE_WRITE_REG(&sc->hw, IXGBE_EICS_EX(0), mask); + mask = (queues >> 32); + IXGBE_WRITE_REG(&sc->hw, IXGBE_EICS_EX(1), mask); + } +} + +static void +ix_handle_que(void *context, int pending) +{ + struct ix_queue *que = context; + struct ix_softc *sc = que->sc; + struct ix_tx_ring *txr = que->txr; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (ifp->if_flags & IFF_RUNNING) { + more = ix_rxeof(que); + ix_txeof(txr); + if (!ifq_is_empty(&ifp->if_snd)) + ixgbe_start_locked(txr, ifp); + } + + /* Reenable this interrupt */ + if (que->res != NULL) + ixgbe_enable_queue(sc, que->msix); + else + ix_enable_intr(sc); + return; +} +#endif + +static void +ix_intr(void *xsc) +{ + struct ix_softc *sc = xsc; + struct ixgbe_hw *hw = &sc->hw; + uint32_t eicr; + + ASSERT_SERIALIZED(&sc->main_serialize); + + eicr = IXGBE_READ_REG(hw, IXGBE_EICR); + if (eicr == 0) { + IXGBE_WRITE_REG(hw, IXGBE_EIMS, sc->intr_mask); + return; + } + + if (eicr & IX_RX0_INTR_MASK) { + struct ix_rx_ring *rxr = &sc->rx_rings[0]; + + lwkt_serialize_enter(&rxr->rx_serialize); + ix_rxeof(rxr); + lwkt_serialize_exit(&rxr->rx_serialize); + } + if (eicr & IX_RX1_INTR_MASK) { + struct ix_rx_ring *rxr; + + KKASSERT(sc->rx_ring_inuse == IX_MIN_RXRING_RSS); + rxr = &sc->rx_rings[1]; + + lwkt_serialize_enter(&rxr->rx_serialize); + ix_rxeof(rxr); + lwkt_serialize_exit(&rxr->rx_serialize); + } + + if (eicr & IX_TX_INTR_MASK) { + struct ix_tx_ring *txr = &sc->tx_rings[0]; + + lwkt_serialize_enter(&txr->tx_serialize); + ix_txeof(txr); + if (!ifsq_is_empty(txr->tx_ifsq)) + ifsq_devstart(txr->tx_ifsq); + lwkt_serialize_exit(&txr->tx_serialize); + } + + /* Check for fan failure */ + if (__predict_false((eicr & IXGBE_EICR_GPI_SDP1) && + hw->phy.media_type == ixgbe_media_type_copper)) { + if_printf(&sc->arpcom.ac_if, "CRITICAL: FAN FAILURE!! " + "REPLACE IMMEDIATELY!!\n"); + } + + /* Link status change */ + if (__predict_false(eicr & IXGBE_EICR_LSC)) + ix_handle_link(sc); + + IXGBE_WRITE_REG(hw, IXGBE_EIMS, sc->intr_mask); +} + +#if 0 +/********************************************************************* + * + * MSIX Queue Interrupt Service routine + * + **********************************************************************/ +void +ix_msix_que(void *arg) +{ + struct ix_queue *que = arg; + struct ix_softc *sc = que->sc; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ix_tx_ring *txr = que->txr; + struct ix_rx_ring *rxr = que->rxr; + uint32_t newitr = 0; + + ixgbe_disable_queue(sc, que->msix); + ++que->irqs; + + more = ix_rxeof(que); + + ix_txeof(txr); + if (!ifq_is_empty(&ifp->if_snd)) + ixgbe_start_locked(txr, ifp); + + /* Do AIM now? */ + + if (ixgbe_enable_aim == FALSE) + goto no_calc; + /* + ** Do Adaptive Interrupt Moderation: + ** - Write out last calculated setting + ** - Calculate based on average size over + ** the last interval. + */ + if (que->eitr_setting) + IXGBE_WRITE_REG(&sc->hw, + IXGBE_EITR(que->msix), que->eitr_setting); + + que->eitr_setting = 0; + + /* Idle, do nothing */ + if ((txr->bytes == 0) && (rxr->bytes == 0)) + goto no_calc; + + if ((txr->bytes) && (txr->packets)) + newitr = txr->bytes/txr->packets; + if ((rxr->bytes) && (rxr->packets)) + newitr = max(newitr, + (rxr->bytes / rxr->packets)); + newitr += 24; /* account for hardware frame, crc */ + + /* set an upper boundary */ + newitr = min(newitr, 3000); + + /* Be nice to the mid range */ + if ((newitr > 300) && (newitr < 1200)) + newitr = (newitr / 3); + else + newitr = (newitr / 2); + + if (sc->hw.mac.type == ixgbe_mac_82598EB) + newitr |= newitr << 16; + else + newitr |= IXGBE_EITR_CNT_WDIS; + + /* save for next interrupt */ + que->eitr_setting = newitr; + + /* Reset state */ + txr->bytes = 0; + txr->packets = 0; + rxr->bytes = 0; + rxr->packets = 0; + +no_calc: +#if 0 + if (more) + taskqueue_enqueue(que->tq, &que->que_task); + else +#endif + ixgbe_enable_queue(sc, que->msix); + return; +} + + +static void +ix_msix_link(void *arg) +{ + struct ix_softc *sc = arg; + struct ixgbe_hw *hw = &sc->hw; + uint32_t reg_eicr; + + ++sc->link_irq; + + /* First get the cause */ + reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); + /* Clear interrupt with write */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); + +#if 0 + /* Link status change */ + if (reg_eicr & IXGBE_EICR_LSC) + taskqueue_enqueue(sc->tq, &sc->link_task); +#endif + + if (sc->hw.mac.type != ixgbe_mac_82598EB) { + if (reg_eicr & IXGBE_EICR_ECC) { + device_printf(sc->dev, "\nCRITICAL: ECC ERROR!! " + "Please Reboot!!\n"); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); + } else + + if (reg_eicr & IXGBE_EICR_GPI_SDP1) { + /* Clear the interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); +#if 0 + taskqueue_enqueue(sc->tq, &sc->msf_task); +#endif + } else if (reg_eicr & IXGBE_EICR_GPI_SDP2) { + /* Clear the interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); +#if 0 + taskqueue_enqueue(sc->tq, &sc->mod_task); +#endif + } + } + + /* Check for fan failure */ + if ((hw->device_id == IXGBE_DEV_ID_82598AT) && + (reg_eicr & IXGBE_EICR_GPI_SDP1)) { + device_printf(sc->dev, "\nCRITICAL: FAN FAILURE!! " + "REPLACE IMMEDIATELY!!\n"); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); + } + + /* Check for over temp condition */ + if ((hw->mac.type == ixgbe_mac_X540) && + (reg_eicr & IXGBE_EICR_TS)) { + device_printf(sc->dev, "\nCRITICAL: OVER TEMP!! " + "PHY IS SHUT DOWN!!\n"); + device_printf(sc->dev, "System shutdown required\n"); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); + } + + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); + return; +} + +#endif + +static void +ix_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct ix_softc *sc = ifp->if_softc; + + ix_update_link_status(sc); + + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_active = IFM_ETHER; + + if (!sc->link_active) + return; + + ifmr->ifm_status |= IFM_ACTIVE; + + switch (sc->link_speed) { + case IXGBE_LINK_SPEED_100_FULL: + ifmr->ifm_active |= IFM_100_TX | IFM_FDX; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + ifmr->ifm_active |= IFM_1000_SX | IFM_FDX; + break; + case IXGBE_LINK_SPEED_10GB_FULL: + ifmr->ifm_active |= sc->optics | IFM_FDX; + break; + } +} + +static int +ix_media_change(struct ifnet *ifp) +{ + struct ix_softc *sc = ifp->if_softc; + struct ifmedia *ifm = &sc->media; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return EINVAL; + + switch (IFM_SUBTYPE(ifm->ifm_media)) { + case IFM_AUTO: + sc->hw.phy.autoneg_advertised = + IXGBE_LINK_SPEED_100_FULL | + IXGBE_LINK_SPEED_1GB_FULL | + IXGBE_LINK_SPEED_10GB_FULL; + break; + default: + if_printf(ifp, "Only auto media type\n"); + return EINVAL; + } + return 0; +} + +static __inline int +ix_tso_pullup(struct mbuf **mp) +{ + int hoff, iphlen, thoff; + struct mbuf *m; + + m = *mp; + KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); + + iphlen = m->m_pkthdr.csum_iphlen; + thoff = m->m_pkthdr.csum_thlen; + hoff = m->m_pkthdr.csum_lhlen; + + KASSERT(iphlen > 0, ("invalid ip hlen")); + KASSERT(thoff > 0, ("invalid tcp hlen")); + KASSERT(hoff > 0, ("invalid ether hlen")); + + if (__predict_false(m->m_len < hoff + iphlen + thoff)) { + m = m_pullup(m, hoff + iphlen + thoff); + if (m == NULL) { + *mp = NULL; + return ENOBUFS; + } + *mp = m; + } + return 0; +} + +static int +ix_encap(struct ix_tx_ring *txr, struct mbuf **m_headp, + uint16_t *segs_used, int *idx) +{ + uint32_t olinfo_status = 0, cmd_type_len, cmd_rs = 0; + int i, j, error, nsegs, first, maxsegs; + struct mbuf *m_head = *m_headp; + bus_dma_segment_t segs[IX_MAX_SCATTER]; + bus_dmamap_t map; + struct ix_tx_buf *txbuf; + union ixgbe_adv_tx_desc *txd = NULL; + + if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { + error = ix_tso_pullup(m_headp); + if (__predict_false(error)) + return error; + m_head = *m_headp; + } + + /* Basic descriptor defines */ + cmd_type_len = (IXGBE_ADVTXD_DTYP_DATA | + IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT); + + if (m_head->m_flags & M_VLANTAG) + cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE; + + /* + * 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->tx_next_avail; + txbuf = &txr->tx_buf[first]; + map = txbuf->map; + + /* + * Map the packet for DMA. + */ + maxsegs = txr->tx_avail - IX_TX_RESERVED; + if (maxsegs > IX_MAX_SCATTER) + maxsegs = IX_MAX_SCATTER; + + error = bus_dmamap_load_mbuf_defrag(txr->tx_tag, map, m_headp, + segs, maxsegs, &nsegs, BUS_DMA_NOWAIT); + if (__predict_false(error)) { + m_freem(*m_headp); + *m_headp = NULL; + return error; + } + bus_dmamap_sync(txr->tx_tag, map, BUS_DMASYNC_PREWRITE); + + m_head = *m_headp; + + /* + * Set up the appropriate offload context if requested, + * this may consume one TX descriptor. + */ + if (ix_tx_ctx_setup(txr, m_head, &cmd_type_len, &olinfo_status)) { + (*segs_used)++; + txr->tx_nsegs++; + } + + *segs_used += nsegs; + txr->tx_nsegs += nsegs; + if (txr->tx_nsegs >= txr->tx_intr_nsegs) { + /* + * Report Status (RS) is turned on every intr_nsegs + * descriptors (roughly). + */ + txr->tx_nsegs = 0; + cmd_rs = IXGBE_TXD_CMD_RS; + } + + i = txr->tx_next_avail; + for (j = 0; j < nsegs; j++) { + bus_size_t seglen; + bus_addr_t segaddr; + + txbuf = &txr->tx_buf[i]; + txd = &txr->tx_base[i]; + seglen = segs[j].ds_len; + segaddr = htole64(segs[j].ds_addr); + + txd->read.buffer_addr = segaddr; + txd->read.cmd_type_len = htole32(IXGBE_TXD_CMD_IFCS | + cmd_type_len |seglen); + txd->read.olinfo_status = htole32(olinfo_status); + + if (++i == txr->tx_ndesc) + i = 0; + } + txd->read.cmd_type_len |= htole32(IXGBE_TXD_CMD_EOP | cmd_rs); + + txr->tx_avail -= nsegs; + txr->tx_next_avail = i; + + txbuf->m_head = m_head; + txr->tx_buf[first].map = txbuf->map; + txbuf->map = map; + + /* + * Defer TDT updating, until enough descrptors are setup + */ + *idx = i; + + return 0; +} + +static void +ix_set_promisc(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + uint32_t reg_rctl; + int mcnt = 0; + + reg_rctl = IXGBE_READ_REG(&sc->hw, IXGBE_FCTRL); + reg_rctl &= ~IXGBE_FCTRL_UPE; + if (ifp->if_flags & IFF_ALLMULTI) { + mcnt = IX_MAX_MCASTADDR; + } else { + struct ifmultiaddr *ifma; + + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (mcnt == IX_MAX_MCASTADDR) + break; + mcnt++; + } + } + if (mcnt < IX_MAX_MCASTADDR) + reg_rctl &= ~IXGBE_FCTRL_MPE; + IXGBE_WRITE_REG(&sc->hw, IXGBE_FCTRL, reg_rctl); + + 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); + } +} + +static void +ix_set_multi(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ifmultiaddr *ifma; + uint32_t fctrl; + uint8_t *mta; + int mcnt = 0; + + mta = sc->mta; + bzero(mta, IXGBE_ETH_LENGTH_OF_ADDRESS * IX_MAX_MCASTADDR); + + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (mcnt == IX_MAX_MCASTADDR) + break; + bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), + &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS], + IXGBE_ETH_LENGTH_OF_ADDRESS); + mcnt++; + } + + 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 (mcnt >= IX_MAX_MCASTADDR || (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); + + if (mcnt < IX_MAX_MCASTADDR) { + ixgbe_update_mc_addr_list(&sc->hw, + mta, mcnt, ix_mc_array_itr, TRUE); + } +} + +/* + * 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 ix_set_multi() one by one. + */ +static uint8_t * +ix_mc_array_itr(struct ixgbe_hw *hw, uint8_t **update_ptr, uint32_t *vmdq) +{ + uint8_t *addr = *update_ptr; + uint8_t *newptr; + *vmdq = 0; + + newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; + *update_ptr = newptr; + return addr; +} + +static void +ix_timer(void *arg) +{ + struct ix_softc *sc = arg; + + lwkt_serialize_enter(&sc->main_serialize); + + if ((sc->arpcom.ac_if.if_flags & IFF_RUNNING) == 0) { + lwkt_serialize_exit(&sc->main_serialize); + return; + } + + /* Check for pluggable optics */ + if (sc->sfp_probe) { + if (!ix_sfp_probe(sc)) + goto done; /* Nothing to do */ + } + + ix_update_link_status(sc); + ix_update_stats(sc); + +done: + callout_reset_bycpu(&sc->timer, hz, ix_timer, sc, sc->timer_cpuid); + lwkt_serialize_exit(&sc->main_serialize); +} + +static void +ix_update_link_status(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->link_up) { + if (sc->link_active == FALSE) { + if (bootverbose) { + if_printf(ifp, "Link is up %d Gbps %s\n", + sc->link_speed == 128 ? 10 : 1, + "Full Duplex"); + } + sc->link_active = TRUE; + + /* Update any Flow Control changes */ + ixgbe_fc_enable(&sc->hw); + + ifp->if_link_state = LINK_STATE_UP; + if_link_state_change(ifp); + } + } else { /* Link down */ + if (sc->link_active == TRUE) { + if (bootverbose) + if_printf(ifp, "Link is Down\n"); + ifp->if_link_state = LINK_STATE_DOWN; + if_link_state_change(ifp); + + sc->link_active = FALSE; + } + } +} + +static void +ix_stop(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + struct ifnet *ifp = &sc->arpcom.ac_if; + int i; + + ASSERT_IFNET_SERIALIZED_ALL(ifp); + + ix_disable_intr(sc); + callout_stop(&sc->timer); + + ifp->if_flags &= ~IFF_RUNNING; + for (i = 0; i < sc->tx_ring_cnt; ++i) { + ifsq_clr_oactive(sc->tx_rings[i].tx_ifsq); + ifsq_watchdog_stop(&sc->tx_rings[i].tx_watchdog); + } + + ixgbe_reset_hw(hw); + hw->adapter_stopped = FALSE; + ixgbe_stop_adapter(hw); + if (hw->mac.type == ixgbe_mac_82599EB) + ixgbe_stop_mac_link_on_d3_82599(hw); + /* Turn off the laser - noop with no optics */ + ixgbe_disable_tx_laser(hw); + + /* Update the stack */ + sc->link_up = FALSE; + ix_update_link_status(sc); + + /* Reprogram the RAR[0] in case user changed it. */ + ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); + + for (i = 0; i < sc->tx_ring_cnt; ++i) + ix_free_tx_ring(&sc->tx_rings[i]); + + for (i = 0; i < sc->rx_ring_cnt; ++i) + ix_free_rx_ring(&sc->rx_rings[i]); +} + +static void +ix_setup_optics(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + int layer; + + layer = ixgbe_get_supported_physical_layer(hw); + + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { + sc->optics = IFM_10G_T; + return; + } + + if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { + sc->optics = IFM_1000_T; + return; + } + + if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) { + sc->optics = IFM_1000_SX; + return; + } + + if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR | + IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) { + sc->optics = IFM_10G_LR; + return; + } + + if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { + sc->optics = IFM_10G_SR; + return; + } + + if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) { + sc->optics = IFM_10G_TWINAX; + return; + } + + if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | + IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) { + sc->optics = IFM_10G_CX4; + return; + } + + /* If we get here just set the default */ + sc->optics = IFM_ETHER | IFM_AUTO; +} + +#if 0 +/********************************************************************* + * + * Setup MSIX Interrupt resources and handlers + * + **********************************************************************/ +static int +ix_allocate_msix(struct ix_softc *sc) +{ + device_t dev = sc->dev; + struct ix_queue *que = sc->queues; + struct ix_tx_ring *txr = sc->tx_rings; + int error, rid, vector = 0; + + for (int i = 0; i < sc->num_queues; i++, vector++, que++, txr++) { + rid = vector + 1; + que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_SHAREABLE | RF_ACTIVE); + if (que->res == NULL) { + device_printf(dev,"Unable to allocate" + " bus resource: que interrupt [%d]\n", vector); + return (ENXIO); + } + /* Set the handler function */ + error = bus_setup_intr(dev, que->res, + INTR_TYPE_NET | INTR_MPSAFE, NULL, + ix_msix_que, que, &que->tag); + if (error) { + que->res = NULL; + device_printf(dev, "Failed to register QUE handler"); + return (error); + } +#if __FreeBSD_version >= 800504 + bus_describe_intr(dev, que->res, que->tag, "que %d", i); +#endif + que->msix = vector; + sc->que_mask |= (uint64_t)(1 << que->msix); + /* + ** Bind the msix vector, and thus the + ** ring to the corresponding cpu. + */ + if (sc->num_queues > 1) + bus_bind_intr(dev, que->res, i); + + TASK_INIT(&que->que_task, 0, ix_handle_que, que); + que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, + taskqueue_thread_enqueue, &que->tq); + taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", + device_get_nameunit(sc->dev)); + } + + /* and Link */ + rid = vector + 1; + sc->res = bus_alloc_resource_any(dev, + SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); + if (!sc->res) { + device_printf(dev,"Unable to allocate" + " bus resource: Link interrupt [%d]\n", rid); + return (ENXIO); + } + /* Set the link handler function */ + error = bus_setup_intr(dev, sc->res, + INTR_TYPE_NET | INTR_MPSAFE, NULL, + ix_msix_link, sc, &sc->tag); + if (error) { + sc->res = NULL; + device_printf(dev, "Failed to register LINK handler"); + return (error); + } +#if __FreeBSD_version >= 800504 + bus_describe_intr(dev, sc->res, sc->tag, "link"); +#endif + sc->linkvec = vector; + /* Tasklets for Link, SFP and Multispeed Fiber */ + TASK_INIT(&sc->link_task, 0, ix_handle_link, sc); + TASK_INIT(&sc->mod_task, 0, ix_handle_mod, sc); + TASK_INIT(&sc->msf_task, 0, ix_handle_msf, sc); + sc->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, + taskqueue_thread_enqueue, &sc->tq); + taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s linkq", + device_get_nameunit(sc->dev)); + + return (0); +} + +static int +ix_setup_msix(struct ix_softc *sc) +{ + device_t dev = sc->dev; + int rid, want, queues, msgs; + + /* Override by tuneable */ + if (ixgbe_enable_msix == 0) + goto msi; + + /* First try MSI/X */ + rid = PCIR_BAR(MSIX_82598_BAR); + sc->msix_mem = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (!sc->msix_mem) { + rid += 4; /* 82599 maps in higher BAR */ + sc->msix_mem = bus_alloc_resource_any(dev, + SYS_RES_MEMORY, &rid, RF_ACTIVE); + } + if (!sc->msix_mem) { + /* May not be enabled */ + device_printf(sc->dev, + "Unable to map MSIX table \n"); + goto msi; + } + + msgs = pci_msix_count(dev); + if (msgs == 0) { /* system has msix disabled */ + bus_release_resource(dev, SYS_RES_MEMORY, + rid, sc->msix_mem); + sc->msix_mem = NULL; + goto msi; + } + + /* Figure out a reasonable auto config value */ + queues = (mp_ncpus > (msgs-1)) ? (msgs-1) : mp_ncpus; + + if (ixgbe_num_queues != 0) + queues = ixgbe_num_queues; + /* Set max queues to 8 when autoconfiguring */ + else if ((ixgbe_num_queues == 0) && (queues > 8)) + queues = 8; + + /* + ** Want one vector (RX/TX pair) per queue + ** plus an additional for Link. + */ + want = queues + 1; + if (msgs >= want) + msgs = want; + else { + device_printf(sc->dev, + "MSIX Configuration Problem, " + "%d vectors but %d queues wanted!\n", + msgs, want); + return (0); /* Will go to Legacy setup */ + } + if ((msgs) && pci_alloc_msix(dev, &msgs) == 0) { + device_printf(sc->dev, + "Using MSIX interrupts with %d vectors\n", msgs); + sc->num_queues = queues; + return (msgs); + } +msi: + msgs = pci_msi_count(dev); + if (msgs == 1 && pci_alloc_msi(dev, &msgs) == 0) + device_printf(sc->dev,"Using an MSI interrupt\n"); + else + device_printf(sc->dev,"Using a Legacy interrupt\n"); + return (msgs); +} +#endif + +static void +ix_setup_ifp(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + struct ifnet *ifp = &sc->arpcom.ac_if; + int i; + + ifp->if_baudrate = IF_Gbps(10UL); + + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_init = ix_init; + ifp->if_ioctl = ix_ioctl; + ifp->if_start = ix_start; + ifp->if_serialize = ix_serialize; + ifp->if_deserialize = ix_deserialize; + ifp->if_tryserialize = ix_tryserialize; +#ifdef INVARIANTS + ifp->if_serialize_assert = ix_serialize_assert; +#endif + + ifq_set_maxlen(&ifp->if_snd, sc->tx_rings[0].tx_ndesc - 2); + ifq_set_ready(&ifp->if_snd); + ifq_set_subq_cnt(&ifp->if_snd, sc->tx_ring_cnt); + + ifp->if_mapsubq = ifq_mapsubq_mask; + ifq_set_subq_mask(&ifp->if_snd, 0); + + ether_ifattach(ifp, hw->mac.addr, NULL); + + ifp->if_capabilities = + IFCAP_HWCSUM | IFCAP_TSO | IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; + if (IX_ENABLE_HWRSS(sc)) + ifp->if_capabilities |= IFCAP_RSS; + ifp->if_capenable = ifp->if_capabilities; + ifp->if_hwassist = CSUM_OFFLOAD | CSUM_TSO; + + /* + * Tell the upper layer(s) we support long frames. + */ + ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); + + /* Setup TX rings and subqueues */ + for (i = 0; i < sc->tx_ring_cnt; ++i) { + struct ifaltq_subque *ifsq = ifq_get_subq(&ifp->if_snd, i); + struct ix_tx_ring *txr = &sc->tx_rings[i]; + + ifsq_set_cpuid(ifsq, txr->tx_intr_cpuid); + ifsq_set_priv(ifsq, txr); + ifsq_set_hw_serialize(ifsq, &txr->tx_serialize); + txr->tx_ifsq = ifsq; + + ifsq_watchdog_init(&txr->tx_watchdog, ifsq, ix_watchdog); + } + + /* + * Specify the media types supported by this adapter and register + * callbacks to update media and link information + */ + ifmedia_add(&sc->media, IFM_ETHER | sc->optics, 0, NULL); + ifmedia_set(&sc->media, IFM_ETHER | sc->optics); + if (hw->device_id == IXGBE_DEV_ID_82598AT) { + 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); +} + +static boolean_t +ix_is_sfp(const struct ixgbe_hw *hw) +{ + switch (hw->phy.type) { + case ixgbe_phy_sfp_avago: + case ixgbe_phy_sfp_ftl: + case ixgbe_phy_sfp_intel: + case ixgbe_phy_sfp_unknown: + case ixgbe_phy_sfp_passive_tyco: + case ixgbe_phy_sfp_passive_unknown: + return TRUE; + default: + return FALSE; + } +} + +static void +ix_config_link(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + boolean_t sfp; + + sfp = ix_is_sfp(hw); + if (sfp) { + if (hw->phy.multispeed_fiber) { + hw->mac.ops.setup_sfp(hw); + ixgbe_enable_tx_laser(hw); + ix_handle_msf(sc); + } else { + ix_handle_mod(sc); + } + } else { + uint32_t autoneg, err = 0; + + if (hw->mac.ops.check_link != NULL) { + err = ixgbe_check_link(hw, &sc->link_speed, + &sc->link_up, FALSE); + if (err) + return; + } + + autoneg = hw->phy.autoneg_advertised; + if (!autoneg && hw->mac.ops.get_link_capabilities != NULL) { + bool negotiate; + + err = hw->mac.ops.get_link_capabilities(hw, + &autoneg, &negotiate); + if (err) + return; + } + + if (hw->mac.ops.setup_link != NULL) { + err = hw->mac.ops.setup_link(hw, + autoneg, sc->link_up); + if (err) + return; + } + } +} + +static int +ix_alloc_rings(struct ix_softc *sc) +{ + int error, i; + + /* + * Create top level busdma tag + */ + error = bus_dma_tag_create(NULL, 1, 0, + BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, + BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT, 0, + &sc->parent_tag); + if (error) { + device_printf(sc->dev, "could not create top level DMA tag\n"); + return error; + } + + /* + * Allocate TX descriptor rings and buffers + */ + sc->tx_rings = kmalloc_cachealign( + sizeof(struct ix_tx_ring) * sc->tx_ring_cnt, + M_DEVBUF, M_WAITOK | M_ZERO); + for (i = 0; i < sc->tx_ring_cnt; ++i) { + struct ix_tx_ring *txr = &sc->tx_rings[i]; + + txr->tx_sc = sc; + txr->tx_idx = i; + lwkt_serialize_init(&txr->tx_serialize); + + error = ix_create_tx_ring(txr); + if (error) + return error; + } + + /* + * Allocate RX descriptor rings and buffers + */ + sc->rx_rings = kmalloc_cachealign( + sizeof(struct ix_rx_ring) * sc->rx_ring_cnt, + M_DEVBUF, M_WAITOK | M_ZERO); + for (i = 0; i < sc->rx_ring_cnt; ++i) { + struct ix_rx_ring *rxr = &sc->rx_rings[i]; + + rxr->rx_sc = sc; + rxr->rx_idx = i; + lwkt_serialize_init(&rxr->rx_serialize); + + error = ix_create_rx_ring(rxr); + if (error) + return error; + } + + return 0; +} + +static int +ix_create_tx_ring(struct ix_tx_ring *txr) +{ + int error, i, tsize, ntxd; + + /* + * Validate number of transmit descriptors. It must not exceed + * hardware maximum, and must be multiple of IX_DBA_ALIGN. + */ + ntxd = device_getenv_int(txr->tx_sc->dev, "txd", ix_txd); + if (((ntxd * sizeof(union ixgbe_adv_tx_desc)) % IX_DBA_ALIGN) != 0 || + ntxd < IX_MIN_TXD || ntxd > IX_MAX_TXD) { + device_printf(txr->tx_sc->dev, + "Using %d TX descriptors instead of %d!\n", + IX_DEF_TXD, ntxd); + txr->tx_ndesc = IX_DEF_TXD; + } else { + txr->tx_ndesc = ntxd; + } + + /* + * Allocate TX head write-back buffer + */ + txr->tx_hdr = bus_dmamem_coherent_any(txr->tx_sc->parent_tag, + __VM_CACHELINE_SIZE, __VM_CACHELINE_SIZE, BUS_DMA_WAITOK, + &txr->tx_hdr_dtag, &txr->tx_hdr_map, &txr->tx_hdr_paddr); + if (txr->tx_hdr == NULL) { + device_printf(txr->tx_sc->dev, + "Unable to allocate TX head write-back buffer\n"); + return ENOMEM; + } + + /* + * Allocate TX descriptor ring + */ + tsize = roundup2(txr->tx_ndesc * sizeof(union ixgbe_adv_tx_desc), + IX_DBA_ALIGN); + txr->tx_base = bus_dmamem_coherent_any(txr->tx_sc->parent_tag, + IX_DBA_ALIGN, tsize, BUS_DMA_WAITOK | BUS_DMA_ZERO, + &txr->tx_base_dtag, &txr->tx_base_map, &txr->tx_base_paddr); + if (txr->tx_base == NULL) { + device_printf(txr->tx_sc->dev, + "Unable to allocate TX Descriptor memory\n"); + return ENOMEM; + } + + tsize = __VM_CACHELINE_ALIGN(sizeof(struct ix_tx_buf) * txr->tx_ndesc); + txr->tx_buf = kmalloc_cachealign(tsize, M_DEVBUF, M_WAITOK | M_ZERO); + + /* + * Create DMA tag for TX buffers + */ + error = bus_dma_tag_create(txr->tx_sc->parent_tag, + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + IX_TSO_SIZE, /* maxsize */ + IX_MAX_SCATTER, /* nsegments */ + PAGE_SIZE, /* maxsegsize */ + BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | + BUS_DMA_ONEBPAGE, /* flags */ + &txr->tx_tag); + if (error) { + device_printf(txr->tx_sc->dev, + "Unable to allocate TX DMA tag\n"); + kfree(txr->tx_buf, M_DEVBUF); + txr->tx_buf = NULL; + return error; + } + + /* + * Create DMA maps for TX buffers + */ + for (i = 0; i < txr->tx_ndesc; ++i) { + struct ix_tx_buf *txbuf = &txr->tx_buf[i]; + + error = bus_dmamap_create(txr->tx_tag, + BUS_DMA_WAITOK | BUS_DMA_ONEBPAGE, &txbuf->map); + if (error) { + device_printf(txr->tx_sc->dev, + "Unable to create TX DMA map\n"); + ix_destroy_tx_ring(txr, i); + return error; + } + } + + /* + * Initialize various watermark + */ + txr->tx_wreg_nsegs = IX_DEF_TXWREG_NSEGS; + txr->tx_intr_nsegs = txr->tx_ndesc / 16; + + return 0; +} + +static void +ix_destroy_tx_ring(struct ix_tx_ring *txr, int ndesc) +{ + int i; + + if (txr->tx_hdr != NULL) { + bus_dmamap_unload(txr->tx_hdr_dtag, txr->tx_hdr_map); + bus_dmamem_free(txr->tx_hdr_dtag, + __DEVOLATILE(void *, txr->tx_hdr), txr->tx_hdr_map); + bus_dma_tag_destroy(txr->tx_hdr_dtag); + txr->tx_hdr = NULL; + } + + if (txr->tx_base != NULL) { + bus_dmamap_unload(txr->tx_base_dtag, txr->tx_base_map); + bus_dmamem_free(txr->tx_base_dtag, txr->tx_base, + txr->tx_base_map); + bus_dma_tag_destroy(txr->tx_base_dtag); + txr->tx_base = NULL; + } + + if (txr->tx_buf == NULL) + return; + + for (i = 0; i < ndesc; ++i) { + struct ix_tx_buf *txbuf = &txr->tx_buf[i]; + + KKASSERT(txbuf->m_head == NULL); + bus_dmamap_destroy(txr->tx_tag, txbuf->map); + } + bus_dma_tag_destroy(txr->tx_tag); + + kfree(txr->tx_buf, M_DEVBUF); + txr->tx_buf = NULL; +} + +static void +ix_init_tx_ring(struct ix_tx_ring *txr) +{ + /* Clear the old ring contents */ + bzero(txr->tx_base, sizeof(union ixgbe_adv_tx_desc) * txr->tx_ndesc); + + /* Clear TX head write-back buffer */ + *(txr->tx_hdr) = 0; + + /* Reset indices */ + txr->tx_next_avail = 0; + txr->tx_next_clean = 0; + txr->tx_nsegs = 0; + + /* Set number of descriptors available */ + txr->tx_avail = txr->tx_ndesc; +} + +static void +ix_init_tx_unit(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + int i; + + /* + * Setup the Base and Length of the Tx Descriptor Ring + */ + for (i = 0; i < sc->tx_ring_inuse; ++i) { + struct ix_tx_ring *txr = &sc->tx_rings[i]; + uint64_t tdba = txr->tx_base_paddr; + uint64_t hdr_paddr = txr->tx_hdr_paddr; + uint32_t txctrl; + + IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), (uint32_t)tdba); + IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (uint32_t)(tdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), + txr->tx_ndesc * sizeof(union ixgbe_adv_tx_desc)); + + /* 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); + + /* Disable TX head write-back relax ordering */ + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: + default: + txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i)); + break; + } + txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: + default: + IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), txctrl); + break; + } + + /* Enable TX head write-back */ + IXGBE_WRITE_REG(hw, IXGBE_TDWBAH(i), + (uint32_t)(hdr_paddr >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_TDWBAL(i), + ((uint32_t)hdr_paddr) | IXGBE_TDWBAL_HEAD_WB_ENABLE); + } + + if (hw->mac.type != ixgbe_mac_82598EB) { + uint32_t dmatxctl, rttdcs; + + dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); + dmatxctl |= IXGBE_DMATXCTL_TE; + IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); + + /* Disable arbiter to set MTQC */ + rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); + rttdcs |= IXGBE_RTTDCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); + + IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); + + /* Reenable aribter */ + rttdcs &= ~IXGBE_RTTDCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); + } +} + +static int +ix_tx_ctx_setup(struct ix_tx_ring *txr, const struct mbuf *mp, + uint32_t *cmd_type_len, uint32_t *olinfo_status) +{ + struct ixgbe_adv_tx_context_desc *TXD; + uint32_t vlan_macip_lens = 0, type_tucmd_mlhl = 0; + int ehdrlen, ip_hlen = 0, ctxd; + boolean_t offload = TRUE; + + /* First check if TSO is to be used */ + if (mp->m_pkthdr.csum_flags & CSUM_TSO) { + return ix_tso_ctx_setup(txr, mp, + cmd_type_len, olinfo_status); + } + + if ((mp->m_pkthdr.csum_flags & CSUM_OFFLOAD) == 0) + offload = FALSE; + + /* Indicate the whole packet as payload when not doing TSO */ + *olinfo_status |= mp->m_pkthdr.len << IXGBE_ADVTXD_PAYLEN_SHIFT; + + /* + * In advanced descriptors the vlan tag must be placed into the + * context descriptor. Hence we need to make one even if not + * doing checksum offloads. + */ + if (mp->m_flags & M_VLANTAG) { + vlan_macip_lens |= htole16(mp->m_pkthdr.ether_vlantag) << + IXGBE_ADVTXD_VLAN_SHIFT; + } else if (!offload) { + /* No TX descriptor is consumed */ + return 0; + } + + /* Set the ether header length */ + ehdrlen = mp->m_pkthdr.csum_lhlen; + KASSERT(ehdrlen > 0, ("invalid ether hlen")); + vlan_macip_lens |= ehdrlen << IXGBE_ADVTXD_MACLEN_SHIFT; + + if (mp->m_pkthdr.csum_flags & CSUM_IP) { + *olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + ip_hlen = mp->m_pkthdr.csum_iphlen; + KASSERT(ip_hlen > 0, ("invalid ip hlen")); + } + vlan_macip_lens |= ip_hlen; + + type_tucmd_mlhl |= IXGBE_ADVTXD_DCMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT; + if (mp->m_pkthdr.csum_flags & CSUM_TCP) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + else if (mp->m_pkthdr.csum_flags & CSUM_UDP) + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_UDP; + + if (mp->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) + *olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; + + /* Now ready a context descriptor */ + ctxd = txr->tx_next_avail; + TXD = (struct ixgbe_adv_tx_context_desc *)&txr->tx_base[ctxd]; + + /* 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); + + /* We've consumed the first desc, adjust counters */ + if (++ctxd == txr->tx_ndesc) + ctxd = 0; + txr->tx_next_avail = ctxd; + --txr->tx_avail; + + /* One TX descriptor is consumed */ + return 1; +} + +static int +ix_tso_ctx_setup(struct ix_tx_ring *txr, const struct mbuf *mp, + uint32_t *cmd_type_len, uint32_t *olinfo_status) +{ + struct ixgbe_adv_tx_context_desc *TXD; + uint32_t vlan_macip_lens = 0, type_tucmd_mlhl = 0; + uint32_t mss_l4len_idx = 0, paylen; + int ctxd, ehdrlen, ip_hlen, tcp_hlen; + + ehdrlen = mp->m_pkthdr.csum_lhlen; + KASSERT(ehdrlen > 0, ("invalid ether hlen")); + + ip_hlen = mp->m_pkthdr.csum_iphlen; + KASSERT(ip_hlen > 0, ("invalid ip hlen")); + + tcp_hlen = mp->m_pkthdr.csum_thlen; + KASSERT(tcp_hlen > 0, ("invalid tcp hlen")); + + ctxd = txr->tx_next_avail; + TXD = (struct ixgbe_adv_tx_context_desc *) &txr->tx_base[ctxd]; + + if (mp->m_flags & M_VLANTAG) { + vlan_macip_lens |= htole16(mp->m_pkthdr.ether_vlantag) << + IXGBE_ADVTXD_VLAN_SHIFT; + } + 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_TUCMD_IPV4; + type_tucmd_mlhl |= IXGBE_ADVTXD_DCMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT; + type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + 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); + + if (++ctxd == txr->tx_ndesc) + ctxd = 0; + + txr->tx_avail--; + txr->tx_next_avail = ctxd; + + *cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; + + /* This is used in the transmit desc in encap */ + paylen = mp->m_pkthdr.len - ehdrlen - ip_hlen - tcp_hlen; + + *olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; + *olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; + *olinfo_status |= paylen << IXGBE_ADVTXD_PAYLEN_SHIFT; + + /* One TX descriptor is consumed */ + return 1; +} + +static void +ix_txeof(struct ix_tx_ring *txr) +{ + struct ifnet *ifp = &txr->tx_sc->arpcom.ac_if; + int first, hdr, avail; + + if (txr->tx_avail == txr->tx_ndesc) + return; + + first = txr->tx_next_clean; + hdr = *(txr->tx_hdr); + + if (first == hdr) + return; + + avail = txr->tx_avail; + while (first != hdr) { + struct ix_tx_buf *txbuf = &txr->tx_buf[first]; + + ++avail; + if (txbuf->m_head) { + bus_dmamap_unload(txr->tx_tag, txbuf->map); + m_freem(txbuf->m_head); + txbuf->m_head = NULL; + IFNET_STAT_INC(ifp, opackets, 1); + } + if (++first == txr->tx_ndesc) + first = 0; + } + txr->tx_next_clean = first; + txr->tx_avail = avail; + + if (txr->tx_avail > IX_MAX_SCATTER + IX_TX_RESERVED) { + ifsq_clr_oactive(txr->tx_ifsq); + txr->tx_watchdog.wd_timer = 0; + } +} + +static int +ix_create_rx_ring(struct ix_rx_ring *rxr) +{ + int i, rsize, error, nrxd; + + /* + * Validate number of receive descriptors. It must not exceed + * hardware maximum, and must be multiple of IX_DBA_ALIGN. + */ + nrxd = device_getenv_int(rxr->rx_sc->dev, "rxd", ix_rxd); + if (((nrxd * sizeof(union ixgbe_adv_rx_desc)) % IX_DBA_ALIGN) != 0 || + nrxd < IX_MIN_RXD || nrxd > IX_MAX_RXD) { + device_printf(rxr->rx_sc->dev, + "Using %d RX descriptors instead of %d!\n", + IX_DEF_RXD, nrxd); + rxr->rx_ndesc = IX_DEF_RXD; + } else { + rxr->rx_ndesc = nrxd; + } + + /* + * Allocate RX descriptor ring + */ + rsize = roundup2(rxr->rx_ndesc * sizeof(union ixgbe_adv_rx_desc), + IX_DBA_ALIGN); + rxr->rx_base = bus_dmamem_coherent_any(rxr->rx_sc->parent_tag, + IX_DBA_ALIGN, rsize, BUS_DMA_WAITOK | BUS_DMA_ZERO, + &rxr->rx_base_dtag, &rxr->rx_base_map, &rxr->rx_base_paddr); + if (rxr->rx_base == NULL) { + device_printf(rxr->rx_sc->dev, + "Unable to allocate TX Descriptor memory\n"); + return ENOMEM; + } + + rsize = __VM_CACHELINE_ALIGN(sizeof(struct ix_rx_buf) * rxr->rx_ndesc); + rxr->rx_buf = kmalloc_cachealign(rsize, M_DEVBUF, M_WAITOK | M_ZERO); + + /* + * Create DMA tag for RX buffers + */ + error = bus_dma_tag_create(rxr->rx_sc->parent_tag, + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + PAGE_SIZE, /* maxsize */ + 1, /* nsegments */ + PAGE_SIZE, /* maxsegsize */ + BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, /* flags */ + &rxr->rx_tag); + if (error) { + device_printf(rxr->rx_sc->dev, + "Unable to create RX DMA tag\n"); + kfree(rxr->rx_buf, M_DEVBUF); + rxr->rx_buf = NULL; + return error; + } + + /* + * Create spare DMA map for RX buffers + */ + error = bus_dmamap_create(rxr->rx_tag, BUS_DMA_WAITOK, + &rxr->rx_sparemap); + if (error) { + device_printf(rxr->rx_sc->dev, + "Unable to create spare RX DMA map\n"); + bus_dma_tag_destroy(rxr->rx_tag); + kfree(rxr->rx_buf, M_DEVBUF); + rxr->rx_buf = NULL; + return error; + } + + /* + * Create DMA maps for RX buffers + */ + for (i = 0; i < rxr->rx_ndesc; ++i) { + struct ix_rx_buf *rxbuf = &rxr->rx_buf[i]; + + error = bus_dmamap_create(rxr->rx_tag, + BUS_DMA_WAITOK, &rxbuf->map); + if (error) { + device_printf(rxr->rx_sc->dev, + "Unable to create RX dma map\n"); + ix_destroy_rx_ring(rxr, i); + return error; + } + } + + /* + * Initialize various watermark + */ + rxr->rx_wreg_nsegs = IX_DEF_RXWREG_NSEGS; + + return 0; +} + +static void +ix_destroy_rx_ring(struct ix_rx_ring *rxr, int ndesc) +{ + int i; + + if (rxr->rx_base != NULL) { + bus_dmamap_unload(rxr->rx_base_dtag, rxr->rx_base_map); + bus_dmamem_free(rxr->rx_base_dtag, rxr->rx_base, + rxr->rx_base_map); + bus_dma_tag_destroy(rxr->rx_base_dtag); + rxr->rx_base = NULL; + } + + if (rxr->rx_buf == NULL) + return; + + for (i = 0; i < ndesc; ++i) { + struct ix_rx_buf *rxbuf = &rxr->rx_buf[i]; + + KKASSERT(rxbuf->m_head == NULL); + bus_dmamap_destroy(rxr->rx_tag, rxbuf->map); + } + bus_dmamap_destroy(rxr->rx_tag, rxr->rx_sparemap); + bus_dma_tag_destroy(rxr->rx_tag); + + kfree(rxr->rx_buf, M_DEVBUF); + rxr->rx_buf = NULL; +} + +/* +** Used to detect a descriptor that has +** been merged by Hardware RSC. +*/ +static __inline uint32_t +ix_rsc_count(union ixgbe_adv_rx_desc *rx) +{ + return (le32toh(rx->wb.lower.lo_dword.data) & + IXGBE_RXDADV_RSCCNT_MASK) >> IXGBE_RXDADV_RSCCNT_SHIFT; +} + +#if 0 +/********************************************************************* + * + * Initialize Hardware RSC (LRO) feature on 82599 + * for an RX ring, this is toggled by the LRO capability + * even though it is transparent to the stack. + * + * NOTE: since this HW feature only works with IPV4 and + * our testing has shown soft LRO to be as effective + * I have decided to disable this by default. + * + **********************************************************************/ +static void +ix_setup_hw_rsc(struct ix_rx_ring *rxr) +{ + struct ix_softc *sc = rxr->rx_sc; + struct ixgbe_hw *hw = &sc->hw; + uint32_t rscctrl, rdrxctl; + +#if 0 + /* If turning LRO/RSC off we need to disable it */ + if ((sc->arpcom.ac_if.if_capenable & IFCAP_LRO) == 0) { + rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(rxr->me)); + rscctrl &= ~IXGBE_RSCCTL_RSCEN; + return; + } +#endif + + rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE; + rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP; + rdrxctl |= IXGBE_RDRXCTL_RSCACKC; + IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); + + rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(rxr->me)); + rscctrl |= IXGBE_RSCCTL_RSCEN; + /* + ** Limit the total number of descriptors that + ** can be combined, so it does not exceed 64K + */ + if (rxr->mbuf_sz == MCLBYTES) + rscctrl |= IXGBE_RSCCTL_MAXDESC_16; + else if (rxr->mbuf_sz == MJUMPAGESIZE) + rscctrl |= IXGBE_RSCCTL_MAXDESC_8; + else if (rxr->mbuf_sz == MJUM9BYTES) + rscctrl |= IXGBE_RSCCTL_MAXDESC_4; + else /* Using 16K cluster */ + rscctrl |= IXGBE_RSCCTL_MAXDESC_1; + + IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(rxr->me), rscctrl); + + /* Enable TCP header recognition */ + IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), + (IXGBE_READ_REG(hw, IXGBE_PSRTYPE(0)) | + IXGBE_PSRTYPE_TCPHDR)); + + /* Disable RSC for ACK packets */ + IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, + (IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU))); + + rxr->hw_rsc = TRUE; +} +#endif + +static int +ix_init_rx_ring(struct ix_rx_ring *rxr) +{ + int i; + + /* Clear the ring contents */ + bzero(rxr->rx_base, rxr->rx_ndesc * sizeof(union ixgbe_adv_rx_desc)); + + /* XXX we need JUMPAGESIZE for RSC too */ + if (rxr->rx_sc->max_frame_size <= MCLBYTES) + rxr->rx_mbuf_sz = MCLBYTES; + else + rxr->rx_mbuf_sz = MJUMPAGESIZE; + + /* Now replenish the mbufs */ + for (i = 0; i < rxr->rx_ndesc; ++i) { + int error; + + error = ix_newbuf(rxr, i, TRUE); + if (error) + return error; + } + + /* Setup our descriptor indices */ + rxr->rx_next_check = 0; + rxr->rx_flags &= ~IX_RXRING_FLAG_DISC; + +#if 0 + /* + ** Now set up the LRO interface: + */ + if (ixgbe_rsc_enable) + ix_setup_hw_rsc(rxr); +#endif + + return 0; +} + +#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 + +#define BSIZEPKT_ROUNDUP ((1<hw; + struct ifnet *ifp = &sc->arpcom.ac_if; + uint32_t bufsz, rxctrl, fctrl, rxcsum, hlreg; + int i; + + /* + * Make sure receives are disabled while setting up the descriptor ring + */ + rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); + + /* Enable broadcasts */ + fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + fctrl |= IXGBE_FCTRL_BAM; + fctrl |= IXGBE_FCTRL_DPF; + fctrl |= IXGBE_FCTRL_PMCF; + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); + + /* Set for Jumbo Frames? */ + hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); + if (ifp->if_mtu > ETHERMTU) + hlreg |= IXGBE_HLREG0_JUMBOEN; + else + hlreg &= ~IXGBE_HLREG0_JUMBOEN; + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); + + KKASSERT(sc->rx_rings[0].rx_mbuf_sz >= MCLBYTES); + bufsz = (sc->rx_rings[0].rx_mbuf_sz + BSIZEPKT_ROUNDUP) >> + IXGBE_SRRCTL_BSIZEPKT_SHIFT; + + for (i = 0; i < sc->rx_ring_inuse; ++i) { + struct ix_rx_ring *rxr = &sc->rx_rings[i]; + uint64_t rdba = rxr->rx_base_paddr; + uint32_t srrctl; + + /* Setup the Base and Length of the Rx Descriptor Ring */ + IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (uint32_t)rdba); + IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (uint32_t)(rdba >> 32)); + IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), + rxr->rx_ndesc * sizeof(union ixgbe_adv_rx_desc)); + + /* + * Set up the SRRCTL register + */ + srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); + + srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; + srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; + srrctl |= bufsz; + srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; + if (sc->rx_ring_inuse > 1) { + /* See the commend near ix_enable_rx_drop() */ + switch (sc->fc) { + case ixgbe_fc_rx_pause: + case ixgbe_fc_tx_pause: + case ixgbe_fc_full: + srrctl &= ~IXGBE_SRRCTL_DROP_EN; + if (i == 0 && bootverbose) { + if_printf(ifp, "flow control %d, " + "disable RX drop\n", sc->fc); + } + break; + + case ixgbe_fc_none: + srrctl |= IXGBE_SRRCTL_DROP_EN; + if (i == 0 && bootverbose) { + if_printf(ifp, "flow control %d, " + "enable RX drop\n", sc->fc); + } + break; + + default: + break; + } + } + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); + + /* Setup the HW Rx Head and Tail Descriptor Pointers */ + IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); + } + + if (sc->hw.mac.type != ixgbe_mac_82598EB) + IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), 0); + + rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); + + /* + * Setup RSS + */ + if (IX_ENABLE_HWRSS(sc)) { + uint8_t key[IX_NRSSRK * IX_RSSRK_SIZE]; + int j, r; + + /* + * NOTE: + * When we reach here, RSS has already been disabled + * in ix_stop(), so we could safely configure RSS key + * and redirect table. + */ + + /* + * Configure RSS key + */ + toeplitz_get_key(key, sizeof(key)); + for (i = 0; i < IX_NRSSRK; ++i) { + uint32_t rssrk; + + rssrk = IX_RSSRK_VAL(key, i); + IX_RSS_DPRINTF(sc, 1, "rssrk%d 0x%08x\n", + i, rssrk); + + IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rssrk); + } + + /* + * Configure RSS redirect table in following fashion: + * (hash & ring_cnt_mask) == rdr_table[(hash & rdr_table_mask)] + */ + r = 0; + for (j = 0; j < IX_NRETA; ++j) { + uint32_t reta = 0; + + for (i = 0; i < IX_RETA_SIZE; ++i) { + uint32_t q; + + q = r % sc->rx_ring_inuse; + reta |= q << (8 * i); + ++r; + } + IX_RSS_DPRINTF(sc, 1, "reta 0x%08x\n", reta); + IXGBE_WRITE_REG(hw, IXGBE_RETA(j), reta); + } + + /* + * Enable multiple receive queues. + * Enable IPv4 RSS standard hash functions. + */ + IXGBE_WRITE_REG(hw, IXGBE_MRQC, + IXGBE_MRQC_RSSEN | + IXGBE_MRQC_RSS_FIELD_IPV4 | + IXGBE_MRQC_RSS_FIELD_IPV4_TCP); + + /* + * NOTE: + * PCSD must be enabled to enable multiple + * receive queues. + */ + rxcsum |= IXGBE_RXCSUM_PCSD; + } + + if (ifp->if_capenable & IFCAP_RXCSUM) + rxcsum |= IXGBE_RXCSUM_PCSD; + + IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); +} + +static __inline void +ix_rx_refresh(struct ix_rx_ring *rxr, int i) +{ + if (--i < 0) + i = rxr->rx_ndesc - 1; + IXGBE_WRITE_REG(&rxr->rx_sc->hw, IXGBE_RDT(rxr->rx_idx), i); +} + +static __inline void +ix_rxcsum(uint32_t staterr, struct mbuf *mp, uint32_t ptype) +{ + if ((ptype & + (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_IPV4_EX)) == 0) { + /* Not IPv4 */ + return; + } + + if ((staterr & (IXGBE_RXD_STAT_IPCS | IXGBE_RXDADV_ERR_IPE)) == + IXGBE_RXD_STAT_IPCS) + mp->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID; + + if ((ptype & + (IXGBE_RXDADV_PKTTYPE_TCP | IXGBE_RXDADV_PKTTYPE_UDP)) == 0) { + /* + * - Neither TCP nor UDP + * - IPv4 fragment + */ + return; + } + + if ((staterr & (IXGBE_RXD_STAT_L4CS | IXGBE_RXDADV_ERR_TCPE)) == + IXGBE_RXD_STAT_L4CS) { + mp->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR | + CSUM_FRAG_NOT_CHECKED; + mp->m_pkthdr.csum_data = htons(0xffff); + } +} + +static __inline struct pktinfo * +ix_rssinfo(struct mbuf *m, struct pktinfo *pi, + uint32_t hash, uint32_t hashtype, uint32_t ptype) +{ + switch (hashtype) { + case IXGBE_RXDADV_RSSTYPE_IPV4_TCP: + pi->pi_netisr = NETISR_IP; + pi->pi_flags = 0; + pi->pi_l3proto = IPPROTO_TCP; + break; + + case IXGBE_RXDADV_RSSTYPE_IPV4: + if ((ptype & IXGBE_RXDADV_PKTTYPE_UDP) == 0) { + /* Not UDP or is fragment */ + return NULL; + } + pi->pi_netisr = NETISR_IP; + pi->pi_flags = 0; + pi->pi_l3proto = IPPROTO_UDP; + break; + + default: + return NULL; + } + + m->m_flags |= M_HASH; + m->m_pkthdr.hash = toeplitz_hash(hash); + return pi; +} + +static __inline void +ix_setup_rxdesc(union ixgbe_adv_rx_desc *rxd, const struct ix_rx_buf *rxbuf) +{ + rxd->read.pkt_addr = htole64(rxbuf->paddr); + rxd->wb.upper.status_error = 0; +} + +static void +ix_rx_discard(struct ix_rx_ring *rxr, int i, boolean_t eop) +{ + struct ix_rx_buf *rxbuf = &rxr->rx_buf[i]; + + /* + * XXX discard may not be correct + */ + if (eop) { + IFNET_STAT_INC(&rxr->rx_sc->arpcom.ac_if, ierrors, 1); + rxr->rx_flags &= ~IX_RXRING_FLAG_DISC; + } else { + rxr->rx_flags |= IX_RXRING_FLAG_DISC; + } + if (rxbuf->fmp != NULL) { + m_freem(rxbuf->fmp); + rxbuf->fmp = NULL; + rxbuf->lmp = NULL; + } + ix_setup_rxdesc(&rxr->rx_base[i], rxbuf); +} + +static void +ix_rxeof(struct ix_rx_ring *rxr) +{ + struct ifnet *ifp = &rxr->rx_sc->arpcom.ac_if; + int i, nsegs = 0; + + i = rxr->rx_next_check; + for (;;) { + struct ix_rx_buf *rxbuf, *nbuf = NULL; + union ixgbe_adv_rx_desc *cur; + struct mbuf *sendmp = NULL, *mp; + struct pktinfo *pi = NULL, pi0; + uint32_t rsc = 0, ptype, staterr, hash, hashtype; + uint16_t len; + boolean_t eop; + + cur = &rxr->rx_base[i]; + staterr = le32toh(cur->wb.upper.status_error); + + if ((staterr & IXGBE_RXD_STAT_DD) == 0) + break; + ++nsegs; + + rxbuf = &rxr->rx_buf[i]; + mp = rxbuf->m_head; + + len = le16toh(cur->wb.upper.length); + ptype = le32toh(cur->wb.lower.lo_dword.data) & + IXGBE_RXDADV_PKTTYPE_MASK; + hash = le32toh(cur->wb.lower.hi_dword.rss); + hashtype = le32toh(cur->wb.lower.lo_dword.data) & + IXGBE_RXDADV_RSSTYPE_MASK; + eop = ((staterr & IXGBE_RXD_STAT_EOP) != 0); + + /* + * Make sure bad packets are discarded + */ + if ((staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) || + (rxr->rx_flags & IX_RXRING_FLAG_DISC)) { + ix_rx_discard(rxr, i, eop); + goto next_desc; + } + + bus_dmamap_sync(rxr->rx_tag, rxbuf->map, BUS_DMASYNC_POSTREAD); + if (ix_newbuf(rxr, i, FALSE) != 0) { + ix_rx_discard(rxr, i, eop); + goto next_desc; + } + + /* + * On 82599 which supports a hardware LRO, packets + * need not be fragmented across sequential descriptors, + * rather the next descriptor is indicated in bits + * of the descriptor. This also means that we might + * proceses more than one packet at a time, something + * that has never been true before, it required + * eliminating global chain pointers in favor of what + * we are doing here. + */ + if (!eop) { + int nextp; + + /* + * Figure out the next descriptor + * of this frame. + */ + if (rxr->rx_flags & IX_RXRING_FLAG_LRO) + rsc = ix_rsc_count(cur); + if (rsc) { /* Get hardware index */ + nextp = ((staterr & + IXGBE_RXDADV_NEXTP_MASK) >> + IXGBE_RXDADV_NEXTP_SHIFT); + } else { /* Just sequential */ + nextp = i + 1; + if (nextp == rxr->rx_ndesc) + nextp = 0; + } + nbuf = &rxr->rx_buf[nextp]; + prefetch(nbuf); + } + mp->m_len = len; + + /* + * Rather than using the fmp/lmp global pointers + * we now keep the head of a packet chain in the + * buffer struct and pass this along from one + * descriptor to the next, until we get EOP. + */ + if (rxbuf->fmp == NULL) { + mp->m_pkthdr.len = len; + rxbuf->fmp = mp; + rxbuf->lmp = mp; + } else { + rxbuf->fmp->m_pkthdr.len += len; + rxbuf->lmp->m_next = mp; + rxbuf->lmp = mp; + } + + if (nbuf != NULL) { + /* + * Not the last fragment of this frame, + * pass this fragment list on + */ + nbuf->fmp = rxbuf->fmp; + nbuf->lmp = rxbuf->lmp; + } else { + /* + * Send this frame + */ + sendmp = rxbuf->fmp; + + sendmp->m_pkthdr.rcvif = ifp; + IFNET_STAT_INC(ifp, ipackets, 1); +#ifdef IX_RSS_DEBUG + rxr->rx_pkts++; +#endif + + /* Process vlan info */ + if (staterr & IXGBE_RXD_STAT_VP) { + sendmp->m_pkthdr.ether_vlantag = + le16toh(cur->wb.upper.vlan); + sendmp->m_flags |= M_VLANTAG; + } + if (ifp->if_capenable & IFCAP_RXCSUM) + ix_rxcsum(staterr, sendmp, ptype); + if (ifp->if_capenable & IFCAP_RSS) { + pi = ix_rssinfo(sendmp, &pi0, + hash, hashtype, ptype); + } + } + rxbuf->fmp = NULL; + rxbuf->lmp = NULL; +next_desc: + /* Advance our pointers to the next descriptor. */ + if (++i == rxr->rx_ndesc) + i = 0; + + if (sendmp != NULL) + ether_input_pkt(ifp, sendmp, pi); + + if (nsegs >= rxr->rx_wreg_nsegs) { + ix_rx_refresh(rxr, i); + nsegs = 0; + } + } + rxr->rx_next_check = i; + + if (nsegs > 0) + ix_rx_refresh(rxr, i); +} + +static void +ix_set_vlan(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + uint32_t ctrl; + + if (hw->mac.type == ixgbe_mac_82598EB) { + ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + ctrl |= IXGBE_VLNCTRL_VME; + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); + } else { + int i; + + /* + * On 82599 and later chips the VLAN enable is + * per queue in RXDCTL + */ + for (i = 0; i < sc->rx_ring_inuse; ++i) { + ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); + ctrl |= IXGBE_RXDCTL_VME; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl); + } + } +} + +static void +ix_enable_intr(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + uint32_t mask, fwsm; + int i; + + for (i = 0; i < sc->intr_cnt; ++i) + lwkt_serialize_handler_enable(sc->intr_data[i].intr_serialize); + + mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); + + /* Enable Fan Failure detection */ + if (hw->device_id == IXGBE_DEV_ID_82598AT) + mask |= IXGBE_EIMS_GPI_SDP1; + + switch (sc->hw.mac.type) { + case ixgbe_mac_82599EB: + mask |= IXGBE_EIMS_ECC; + mask |= IXGBE_EIMS_GPI_SDP0; + mask |= IXGBE_EIMS_GPI_SDP1; + mask |= IXGBE_EIMS_GPI_SDP2; + break; + case ixgbe_mac_X540: + mask |= IXGBE_EIMS_ECC; + /* Detect if Thermal Sensor is enabled */ + fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); + if (fwsm & IXGBE_FWSM_TS_ENABLED) + mask |= IXGBE_EIMS_TS; + /* FALL THROUGH */ + default: + break; + } + sc->intr_mask = mask; + + /* With MSI-X we use auto clear */ + if (sc->intr_type == PCI_INTR_TYPE_MSIX) { + mask = IXGBE_EIMS_ENABLE_MASK; + /* Don't autoclear Link */ + mask &= ~IXGBE_EIMS_OTHER; + mask &= ~IXGBE_EIMS_LSC; + IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); + } else { + sc->intr_mask |= IX_TX_INTR_MASK | + IX_RX0_INTR_MASK; + + KKASSERT(sc->rx_ring_inuse <= IX_MIN_RXRING_RSS); + if (sc->rx_ring_inuse == IX_MIN_RXRING_RSS) + sc->intr_mask |= IX_RX1_INTR_MASK; + } + +#if 0 + /* + ** Now enable all queues, this is done separately to + ** allow for handling the extended (beyond 32) MSIX + ** vectors that can be used by 82599 + */ + for (int i = 0; i < sc->num_queues; i++, que++) + ixgbe_enable_queue(sc, que->msix); +#else + IXGBE_WRITE_REG(hw, IXGBE_EIMS, sc->intr_mask); +#endif + + IXGBE_WRITE_FLUSH(hw); +} + +static void +ix_disable_intr(struct ix_softc *sc) +{ + int i; + +#if 0 + if (sc->msix_mem) + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIAC, 0); +#endif + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC, ~0); + } else { + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC, 0xFFFF0000); + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC_EX(0), ~0); + IXGBE_WRITE_REG(&sc->hw, IXGBE_EIMC_EX(1), ~0); + } + IXGBE_WRITE_FLUSH(&sc->hw); + + for (i = 0; i < sc->intr_cnt; ++i) + lwkt_serialize_handler_disable(sc->intr_data[i].intr_serialize); +} + +uint16_t +ixgbe_read_pci_cfg(struct ixgbe_hw *hw, uint32_t reg) +{ + return pci_read_config(((struct ixgbe_osdep *)hw->back)->dev, + reg, 2); +} + +void +ixgbe_write_pci_cfg(struct ixgbe_hw *hw, uint32_t reg, uint16_t value) +{ + pci_write_config(((struct ixgbe_osdep *)hw->back)->dev, + reg, value, 2); +} + +static void +ix_slot_info(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + device_t dev = sc->dev; + struct ixgbe_mac_info *mac = &hw->mac; + uint16_t link; + uint32_t offset; + + /* For most devices simply call the shared code routine */ + if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) { + ixgbe_get_bus_info(hw); + goto display; + } + + /* + * For the Quad port adapter we need to parse back + * up the PCI tree to find the speed of the expansion + * slot into which this adapter is plugged. A bit more work. + */ + dev = device_get_parent(device_get_parent(dev)); +#ifdef IXGBE_DEBUG + device_printf(dev, "parent pcib = %x,%x,%x\n", + pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); +#endif + dev = device_get_parent(device_get_parent(dev)); +#ifdef IXGBE_DEBUG + device_printf(dev, "slot pcib = %x,%x,%x\n", + pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); +#endif + /* Now get the PCI Express Capabilities offset */ + offset = pci_get_pciecap_ptr(dev); + /* ...and read the Link Status Register */ + link = pci_read_config(dev, offset + PCIER_LINKSTAT, 2); + switch (link & 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 & 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; + case IXGBE_PCI_LINK_SPEED_8000: + hw->bus.speed = ixgbe_bus_speed_8000; + break; + default: + hw->bus.speed = ixgbe_bus_speed_unknown; + break; + } + + mac->ops.set_lan_id(hw); + +display: + device_printf(dev, "PCI Express Bus: Speed %s %s\n", + hw->bus.speed == ixgbe_bus_speed_8000 ? "8.0GT/s" : + hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" : + hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5GT/s" : "Unknown", + hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" : + hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" : + hw->bus.width == ixgbe_bus_width_pcie_x1 ? "Width x1" : "Unknown"); + + if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP && + hw->bus.width <= ixgbe_bus_width_pcie_x4 && + hw->bus.speed == ixgbe_bus_speed_2500) { + device_printf(dev, "For optimal performance a x8 " + "PCIE, or x4 PCIE Gen2 slot is required.\n"); + } else if (hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP && + hw->bus.width <= ixgbe_bus_width_pcie_x8 && + hw->bus.speed < ixgbe_bus_speed_8000) { + device_printf(dev, "For optimal performance a x8 " + "PCIE Gen3 slot is required.\n"); + } +} + +/* + * TODO comment is incorrect + * + * Setup the correct IVAR register for a particular MSIX interrupt + * - entry is the register array entry + * - vector is the MSIX vector for this queue + * - type is RX/TX/MISC + */ +static void +ix_set_ivar(struct ix_softc *sc, uint8_t entry, uint8_t vector, + int8_t type) +{ + struct ixgbe_hw *hw = &sc->hw; + uint32_t ivar, index; + + vector |= IXGBE_IVAR_ALLOC_VAL; + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + if (type == -1) + entry = IXGBE_IVAR_OTHER_CAUSES_INDEX; + else + entry += (type * 64); + index = (entry >> 2) & 0x1F; + ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); + ivar &= ~(0xFF << (8 * (entry & 0x3))); + ivar |= (vector << (8 * (entry & 0x3))); + IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar); + break; + + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: + if (type == -1) { /* MISC IVAR */ + index = (entry & 1) * 8; + ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); + ivar &= ~(0xFF << index); + ivar |= (vector << index); + IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); + } else { /* RX/TX IVARS */ + index = (16 * (entry & 1)) + (8 * type); + ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); + ivar &= ~(0xFF << index); + ivar |= (vector << index); + IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar); + } + + default: + break; + } +} + +#if 0 +static void +ix_configure_ivars(struct ix_softc *sc) +{ + struct ix_queue *que = sc->queues; + uint32_t newitr; + + if (ixgbe_max_interrupt_rate > 0) + newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; + else + newitr = 0; + + for (int i = 0; i < sc->num_queues; i++, que++) { + /* First the RX queue entry */ + ix_set_ivar(sc, i, que->msix, 0); + /* ... and the TX */ + ix_set_ivar(sc, i, que->msix, 1); + /* Set an Initial EITR value */ + IXGBE_WRITE_REG(&sc->hw, + IXGBE_EITR(que->msix), newitr); + } + + /* For the Link interrupt */ + ix_set_ivar(sc, 1, sc->linkvec, -1); +} +#endif + +static boolean_t +ix_sfp_probe(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + + if (hw->phy.type == ixgbe_phy_nl && + hw->phy.sfp_type == ixgbe_sfp_type_not_present) { + int32_t ret; + + ret = hw->phy.ops.identify_sfp(hw); + if (ret) + return FALSE; + + ret = hw->phy.ops.reset(hw); + if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { + if_printf(&sc->arpcom.ac_if, + "Unsupported SFP+ module detected! " + "Reload driver with supported module.\n"); + sc->sfp_probe = FALSE; + return FALSE; + } + if_printf(&sc->arpcom.ac_if, "SFP+ module detected!\n"); + + /* We now have supported optics */ + sc->sfp_probe = FALSE; + /* Set the optics type so system reports correctly */ + ix_setup_optics(sc); + + return TRUE; + } + return FALSE; +} + +static void +ix_handle_link(struct ix_softc *sc) +{ + ixgbe_check_link(&sc->hw, &sc->link_speed, &sc->link_up, 0); + ix_update_link_status(sc); +} + +/* + * Handling SFP module + */ +static void +ix_handle_mod(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + uint32_t err; + + err = hw->phy.ops.identify_sfp(hw); + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + if_printf(&sc->arpcom.ac_if, + "Unsupported SFP+ module type was detected.\n"); + return; + } + err = hw->mac.ops.setup_sfp(hw); + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + if_printf(&sc->arpcom.ac_if, + "Setup failure - unsupported SFP+ module type.\n"); + return; + } + ix_handle_msf(sc); +} + +/* + * Handling MSF (multispeed fiber) + */ +static void +ix_handle_msf(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + uint32_t autoneg; + + autoneg = hw->phy.autoneg_advertised; + if (!autoneg && hw->mac.ops.get_link_capabilities != NULL) { + bool negotiate; + + hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate); + } + if (hw->mac.ops.setup_link != NULL) + hw->mac.ops.setup_link(hw, autoneg, TRUE); +} + +static void +ix_update_stats(struct ix_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ixgbe_hw *hw = &sc->hw; + uint32_t missed_rx = 0, bprc, lxon, lxoff, total; + uint64_t total_missed_rx = 0; + int i; + + sc->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); + sc->stats.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); + sc->stats.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); + sc->stats.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); + + /* + * Note: These are for the 8 possible traffic classes, which + * in current implementation is unused, therefore only 0 should + * read real data. + */ + for (i = 0; i < 8; i++) { + uint32_t mp; + + mp = IXGBE_READ_REG(hw, IXGBE_MPC(i)); + /* missed_rx tallies misses for the gprc workaround */ + missed_rx += mp; + /* global total per queue */ + sc->stats.mpc[i] += mp; + + /* Running comprehensive total for stats display */ + total_missed_rx += sc->stats.mpc[i]; + + if (hw->mac.type == ixgbe_mac_82598EB) { + sc->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i)); + sc->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i)); + sc->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i)); + sc->stats.pxonrxc[i] += + IXGBE_READ_REG(hw, IXGBE_PXONRXC(i)); + } else { + sc->stats.pxonrxc[i] += + IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i)); + } + sc->stats.pxontxc[i] += IXGBE_READ_REG(hw, IXGBE_PXONTXC(i)); + sc->stats.pxofftxc[i] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i)); + sc->stats.pxoffrxc[i] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i)); + sc->stats.pxon2offc[i] += + IXGBE_READ_REG(hw, IXGBE_PXON2OFFCNT(i)); + } + for (i = 0; i < 16; i++) { + sc->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); + sc->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); + sc->stats.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); + } + sc->stats.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC); + sc->stats.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC); + sc->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); + + /* Hardware workaround, gprc counts missed packets */ + sc->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); + sc->stats.gprc -= missed_rx; + + if (hw->mac.type != ixgbe_mac_82598EB) { + sc->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + + ((uint64_t)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); + sc->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + + ((uint64_t)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); + sc->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORL) + + ((uint64_t)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); + sc->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); + sc->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); + } else { + sc->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); + sc->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); + /* 82598 only has a counter in the high register */ + 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); + if (hw->mac.type == ixgbe_mac_82598EB) + sc->stats.mprc -= bprc; + + 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); + + 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.roc += IXGBE_READ_REG(hw, IXGBE_ROC); + sc->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); + sc->stats.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC); + sc->stats.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC); + sc->stats.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC); + sc->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); + sc->stats.tpt += IXGBE_READ_REG(hw, IXGBE_TPT); + 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); + sc->stats.xec += IXGBE_READ_REG(hw, IXGBE_XEC); + sc->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); + sc->stats.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); + /* Only read FCOE on 82599 */ + if (hw->mac.type != ixgbe_mac_82598EB) { + sc->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); + sc->stats.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); + sc->stats.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); + sc->stats.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); + sc->stats.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); + } + + /* Rx Errors */ + IFNET_STAT_SET(ifp, iqdrops, total_missed_rx); + IFNET_STAT_SET(ifp, ierrors, sc->stats.crcerrs + sc->stats.rlec); +} + +#if 0 +/* + * Add sysctl variables, one per statistic, to the system. + */ +static void +ix_add_hw_stats(struct ix_softc *sc) +{ + + device_t dev = sc->dev; + + struct ix_tx_ring *txr = sc->tx_rings; + struct ix_rx_ring *rxr = sc->rx_rings; + + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); + struct sysctl_oid *tree = device_get_sysctl_tree(dev); + struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); + struct ixgbe_hw_stats *stats = &sc->stats; + + struct sysctl_oid *stat_node, *queue_node; + struct sysctl_oid_list *stat_list, *queue_list; + +#define QUEUE_NAME_LEN 32 + char namebuf[QUEUE_NAME_LEN]; + + /* MAC stats get the own sub node */ + + stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", + CTLFLAG_RD, NULL, "MAC Statistics"); + stat_list = SYSCTL_CHILDREN(stat_node); + + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", + CTLFLAG_RD, &stats->crcerrs, + "CRC Errors"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", + CTLFLAG_RD, &stats->illerrc, + "Illegal Byte Errors"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", + CTLFLAG_RD, &stats->errbc, + "Byte Errors"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", + CTLFLAG_RD, &stats->mspdc, + "MAC Short Packets Discarded"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", + CTLFLAG_RD, &stats->mlfc, + "MAC Local Faults"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", + CTLFLAG_RD, &stats->mrfc, + "MAC Remote Faults"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", + CTLFLAG_RD, &stats->rlec, + "Receive Length Errors"); + + /* Flow Control stats */ + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", + CTLFLAG_RD, &stats->lxontxc, + "Link XON Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", + CTLFLAG_RD, &stats->lxonrxc, + "Link XON Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", + CTLFLAG_RD, &stats->lxofftxc, + "Link XOFF Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", + CTLFLAG_RD, &stats->lxoffrxc, + "Link XOFF Received"); + + /* Packet Reception Stats */ + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", + CTLFLAG_RD, &stats->tor, + "Total Octets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", + CTLFLAG_RD, &stats->gorc, + "Good Octets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", + CTLFLAG_RD, &stats->tpr, + "Total Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", + CTLFLAG_RD, &stats->gprc, + "Good Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", + CTLFLAG_RD, &stats->mprc, + "Multicast Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", + CTLFLAG_RD, &stats->bprc, + "Broadcast Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", + CTLFLAG_RD, &stats->prc64, + "64 byte frames received "); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", + CTLFLAG_RD, &stats->prc127, + "65-127 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", + CTLFLAG_RD, &stats->prc255, + "128-255 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", + CTLFLAG_RD, &stats->prc511, + "256-511 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", + CTLFLAG_RD, &stats->prc1023, + "512-1023 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", + CTLFLAG_RD, &stats->prc1522, + "1023-1522 byte frames received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", + CTLFLAG_RD, &stats->ruc, + "Receive Undersized"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", + CTLFLAG_RD, &stats->rfc, + "Fragmented Packets Received "); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", + CTLFLAG_RD, &stats->roc, + "Oversized Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", + CTLFLAG_RD, &stats->rjc, + "Received Jabber"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", + CTLFLAG_RD, &stats->mngprc, + "Management Packets Received"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", + CTLFLAG_RD, &stats->mngptc, + "Management Packets Dropped"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", + CTLFLAG_RD, &stats->xec, + "Checksum Errors"); + + /* Packet Transmission Stats */ + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", + CTLFLAG_RD, &stats->gotc, + "Good Octets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", + CTLFLAG_RD, &stats->tpt, + "Total Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", + CTLFLAG_RD, &stats->gptc, + "Good Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", + CTLFLAG_RD, &stats->bptc, + "Broadcast Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", + CTLFLAG_RD, &stats->mptc, + "Multicast Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", + CTLFLAG_RD, &stats->mngptc, + "Management Packets Transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", + CTLFLAG_RD, &stats->ptc64, + "64 byte frames transmitted "); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", + CTLFLAG_RD, &stats->ptc127, + "65-127 byte frames transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", + CTLFLAG_RD, &stats->ptc255, + "128-255 byte frames transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", + CTLFLAG_RD, &stats->ptc511, + "256-511 byte frames transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", + CTLFLAG_RD, &stats->ptc1023, + "512-1023 byte frames transmitted"); + SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", + CTLFLAG_RD, &stats->ptc1522, + "1024-1522 byte frames transmitted"); +} +#endif + +/* + * Enable the hardware to drop packets when the buffer is full. + * This is useful when multiple RX rings are used, so that no + * single RX ring being full stalls the entire RX engine. We + * only enable this when multiple RX rings are used and when + * flow control is disabled. + */ +static void +ix_enable_rx_drop(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + int i; + + if (bootverbose) { + if_printf(&sc->arpcom.ac_if, + "flow control %d, enable RX drop\n", sc->fc); + } + + for (i = 0; i < sc->rx_ring_inuse; ++i) { + uint32_t srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); + + srrctl |= IXGBE_SRRCTL_DROP_EN; + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); + } +} + +static void +ix_disable_rx_drop(struct ix_softc *sc) +{ + struct ixgbe_hw *hw = &sc->hw; + int i; + + if (bootverbose) { + if_printf(&sc->arpcom.ac_if, + "flow control %d, disable RX drop\n", sc->fc); + } + + for (i = 0; i < sc->rx_ring_inuse; ++i) { + uint32_t srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); + + srrctl &= ~IXGBE_SRRCTL_DROP_EN; + IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); + } +} + +static int +ix_sysctl_flowctrl(SYSCTL_HANDLER_ARGS) +{ + struct ix_softc *sc = (struct ix_softc *)arg1; + struct ifnet *ifp = &sc->arpcom.ac_if; + int error, fc; + + fc = sc->fc; + error = sysctl_handle_int(oidp, &fc, 0, req); + if (error || req->newptr == NULL) + return error; + + switch (fc) { + case ixgbe_fc_rx_pause: + case ixgbe_fc_tx_pause: + case ixgbe_fc_full: + case ixgbe_fc_none: + break; + default: + return EINVAL; + } + + ifnet_serialize_all(ifp); + + /* Don't bother if it's not changed */ + if (sc->fc == fc) + goto done; + sc->fc = fc; + + /* Don't do anything, if the interface is not up yet */ + if ((ifp->if_flags & IFF_RUNNING) == 0) + goto done; + + if (sc->rx_ring_inuse > 1) { + switch (sc->fc) { + case ixgbe_fc_rx_pause: + case ixgbe_fc_tx_pause: + case ixgbe_fc_full: + ix_disable_rx_drop(sc); + break; + + case ixgbe_fc_none: + ix_enable_rx_drop(sc); + break; + + default: + panic("leading fc check mismatch"); + } + } + + sc->hw.fc.requested_mode = sc->fc; + /* Don't autoneg if forcing a value */ + sc->hw.fc.disable_fc_autoneg = TRUE; + ixgbe_fc_enable(&sc->hw); + +done: + ifnet_deserialize_all(ifp); + return error; +} + +#ifdef foo +/* XXX not working properly w/ 82599 connected w/ DAC */ +/* XXX only work after the interface is up */ +static int +ix_sysctl_advspeed(SYSCTL_HANDLER_ARGS) +{ + struct ix_softc *sc = (struct ix_softc *)arg1; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ixgbe_hw *hw = &sc->hw; + ixgbe_link_speed speed; + int error, advspeed; + + advspeed = sc->advspeed; + error = sysctl_handle_int(oidp, &advspeed, 0, req); + if (error || req->newptr == NULL) + return error; + + if (!(hw->phy.media_type == ixgbe_media_type_copper || + hw->phy.multispeed_fiber)) + return EOPNOTSUPP; + if (hw->mac.ops.setup_link == NULL) + return EOPNOTSUPP; + + switch (advspeed) { + case 0: /* auto */ + speed = IXGBE_LINK_SPEED_UNKNOWN; + break; + + case 1: /* 1Gb */ + speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + + case 2: /* 100Mb */ + speed = IXGBE_LINK_SPEED_100_FULL; + break; + + case 3: /* 1Gb/10Gb */ + speed = IXGBE_LINK_SPEED_1GB_FULL | + IXGBE_LINK_SPEED_10GB_FULL; + break; + + default: + return EINVAL; + } + + ifnet_serialize_all(ifp); + + if (sc->advspeed == advspeed) /* no change */ + goto done; + + if ((speed & IXGBE_LINK_SPEED_100_FULL) && + hw->mac.type != ixgbe_mac_X540) { + error = EOPNOTSUPP; + goto done; + } + + sc->advspeed = advspeed; + + if ((ifp->if_flags & IFF_RUNNING) == 0) + goto done; + + if (speed == IXGBE_LINK_SPEED_UNKNOWN) { + ix_config_link(sc); + } else { + hw->mac.autotry_restart = TRUE; + hw->mac.ops.setup_link(hw, speed, sc->link_up); + } + +done: + ifnet_deserialize_all(ifp); + return error; +} +#endif + +static void +ix_setup_serialize(struct ix_softc *sc) +{ + int i = 0, j; + + /* Main + RX + TX */ + sc->nserialize = 1 + sc->rx_ring_cnt + sc->tx_ring_cnt; + sc->serializes = + kmalloc(sc->nserialize * sizeof(struct lwkt_serialize *), + M_DEVBUF, M_WAITOK | M_ZERO); + + /* + * Setup serializes + * + * NOTE: Order is critical + */ + + KKASSERT(i < sc->nserialize); + sc->serializes[i++] = &sc->main_serialize; + + for (j = 0; j < sc->rx_ring_cnt; ++j) { + KKASSERT(i < sc->nserialize); + sc->serializes[i++] = &sc->rx_rings[j].rx_serialize; + } + + for (j = 0; j < sc->tx_ring_cnt; ++j) { + KKASSERT(i < sc->nserialize); + sc->serializes[i++] = &sc->tx_rings[j].tx_serialize; + } + + KKASSERT(i == sc->nserialize); +} + +static int +ix_alloc_intr(struct ix_softc *sc) +{ + struct ix_intr_data *intr; + u_int intr_flags; + int i; + + if (sc->intr_data != NULL) + kfree(sc->intr_data, M_DEVBUF); + + sc->intr_cnt = 1; + sc->intr_data = kmalloc(sizeof(struct ix_intr_data), M_DEVBUF, + M_WAITOK | M_ZERO); + intr = &sc->intr_data[0]; + + /* + * Allocate MSI/legacy interrupt resource + */ + sc->intr_type = pci_alloc_1intr(sc->dev, ix_msi_enable, + &intr->intr_rid, &intr_flags); + + intr->intr_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, + &intr->intr_rid, intr_flags); + if (intr->intr_res == NULL) { + device_printf(sc->dev, "Unable to allocate bus resource: " + "interrupt\n"); + return ENXIO; + } + + intr->intr_serialize = &sc->main_serialize; + intr->intr_cpuid = rman_get_cpuid(intr->intr_res); + intr->intr_func = ix_intr; + intr->intr_funcarg = sc; + intr->intr_rate = IX_INTR_RATE; + intr->intr_use = IX_INTR_USE_RXTX; + + for (i = 0; i < sc->tx_ring_cnt; ++i) { + sc->tx_rings[i].tx_intr_cpuid = intr->intr_cpuid; + sc->tx_rings[i].tx_intr_vec = IX_TX_INTR_VEC; + } + + for (i = 0; i < sc->rx_ring_cnt; ++i) + sc->rx_rings[i].rx_intr_vec = IX_RX0_INTR_VEC; + + ix_set_ring_inuse(sc, FALSE); + + KKASSERT(sc->rx_ring_inuse <= IX_MIN_RXRING_RSS); + if (sc->rx_ring_inuse == IX_MIN_RXRING_RSS) + sc->rx_rings[1].rx_intr_vec = IX_RX1_INTR_VEC; + + return 0; +} + +static void +ix_free_intr(struct ix_softc *sc) +{ + if (sc->intr_data == NULL) + return; + + if (sc->intr_type != PCI_INTR_TYPE_MSIX) { + struct ix_intr_data *intr = &sc->intr_data[0]; + + KKASSERT(sc->intr_cnt == 1); + if (intr->intr_res != NULL) { + bus_release_resource(sc->dev, SYS_RES_IRQ, + intr->intr_rid, intr->intr_res); + } + if (sc->intr_type == PCI_INTR_TYPE_MSI) + pci_release_msi(sc->dev); + } else { + /* TODO */ + } + kfree(sc->intr_data, M_DEVBUF); +} + +static void +ix_set_ring_inuse(struct ix_softc *sc, boolean_t polling) +{ + sc->rx_ring_inuse = ix_get_rxring_inuse(sc, polling); + sc->tx_ring_inuse = ix_get_txring_inuse(sc, polling); + if (bootverbose) { + if_printf(&sc->arpcom.ac_if, + "RX rings %d/%d, TX rings %d/%d\n", + sc->rx_ring_inuse, sc->rx_ring_cnt, + sc->tx_ring_inuse, sc->tx_ring_cnt); + } +} + +static int +ix_get_rxring_inuse(const struct ix_softc *sc, boolean_t polling) +{ + if (!IX_ENABLE_HWRSS(sc)) + return 1; + + if (polling) + return sc->rx_ring_cnt; + else if (sc->intr_type != PCI_INTR_TYPE_MSIX) + return IX_MIN_RXRING_RSS; + else + return 1; /* TODO */ +} + +static int +ix_get_txring_inuse(const struct ix_softc *sc, boolean_t polling) +{ + if (!IX_ENABLE_HWTSS(sc)) + return 1; + + if (polling) + return sc->tx_ring_cnt; + else if (sc->intr_type != PCI_INTR_TYPE_MSIX) + return 1; + else + return 1; /* TODO */ +} + +static int +ix_setup_intr(struct ix_softc *sc) +{ + int i; + + for (i = 0; i < sc->intr_cnt; ++i) { + struct ix_intr_data *intr = &sc->intr_data[i]; + int error; + + error = bus_setup_intr_descr(sc->dev, intr->intr_res, + INTR_MPSAFE, intr->intr_func, intr->intr_funcarg, + &intr->intr_hand, intr->intr_serialize, intr->intr_desc); + if (error) { + device_printf(sc->dev, "can't setup %dth intr\n", i); + ix_teardown_intr(sc, i); + return error; + } + } + return 0; +} + +static void +ix_teardown_intr(struct ix_softc *sc, int intr_cnt) +{ + int i; + + if (sc->intr_data == NULL) + return; + + for (i = 0; i < intr_cnt; ++i) { + struct ix_intr_data *intr = &sc->intr_data[i]; + + bus_teardown_intr(sc->dev, intr->intr_res, intr->intr_hand); + } +} + +static void +ix_serialize(struct ifnet *ifp, enum ifnet_serialize slz) +{ + struct ix_softc *sc = ifp->if_softc; + + ifnet_serialize_array_enter(sc->serializes, sc->nserialize, slz); +} + +static void +ix_deserialize(struct ifnet *ifp, enum ifnet_serialize slz) +{ + struct ix_softc *sc = ifp->if_softc; + + ifnet_serialize_array_exit(sc->serializes, sc->nserialize, slz); +} + +static int +ix_tryserialize(struct ifnet *ifp, enum ifnet_serialize slz) +{ + struct ix_softc *sc = ifp->if_softc; + + return ifnet_serialize_array_try(sc->serializes, sc->nserialize, slz); +} + +#ifdef INVARIANTS + +static void +ix_serialize_assert(struct ifnet *ifp, enum ifnet_serialize slz, + boolean_t serialized) +{ + struct ix_softc *sc = ifp->if_softc; + + ifnet_serialize_array_assert(sc->serializes, sc->nserialize, slz, + serialized); +} + +#endif /* INVARIANTS */ + +static void +ix_free_rings(struct ix_softc *sc) +{ + int i; + + if (sc->tx_rings != NULL) { + for (i = 0; i < sc->tx_ring_cnt; ++i) { + struct ix_tx_ring *txr = &sc->tx_rings[i]; + + ix_destroy_tx_ring(txr, txr->tx_ndesc); + } + kfree(sc->tx_rings, M_DEVBUF); + } + + if (sc->rx_rings != NULL) { + for (i =0; i < sc->rx_ring_cnt; ++i) { + struct ix_rx_ring *rxr = &sc->rx_rings[i]; + + ix_destroy_rx_ring(rxr, rxr->rx_ndesc); + } + kfree(sc->rx_rings, M_DEVBUF); + } + + if (sc->parent_tag != NULL) + bus_dma_tag_destroy(sc->parent_tag); +} + +static void +ix_watchdog(struct ifaltq_subque *ifsq) +{ + struct ix_tx_ring *txr = ifsq_get_priv(ifsq); + struct ifnet *ifp = ifsq_get_ifp(ifsq); + struct ix_softc *sc = ifp->if_softc; + int i; + + KKASSERT(txr->tx_ifsq == ifsq); + ASSERT_IFNET_SERIALIZED_ALL(ifp); + + /* + * If the interface has been paused then don't do the watchdog check + */ + if (IXGBE_READ_REG(&sc->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF) { + txr->tx_watchdog.wd_timer = 5; + return; + } + + if_printf(ifp, "Watchdog timeout -- resetting\n"); + if_printf(ifp, "Queue(%d) tdh = %d, hw tdt = %d\n", txr->tx_idx, + IXGBE_READ_REG(&sc->hw, IXGBE_TDH(txr->tx_idx)), + IXGBE_READ_REG(&sc->hw, IXGBE_TDT(txr->tx_idx))); + if_printf(ifp, "TX(%d) desc avail = %d, next TX to Clean = %d\n", + txr->tx_idx, txr->tx_avail, txr->tx_next_clean); + + ix_init(sc); + for (i = 0; i < sc->tx_ring_inuse; ++i) + ifsq_devstart_sched(sc->tx_rings[i].tx_ifsq); +} + +static void +ix_free_tx_ring(struct ix_tx_ring *txr) +{ + int i; + + for (i = 0; i < txr->tx_ndesc; ++i) { + struct ix_tx_buf *txbuf = &txr->tx_buf[i]; + + if (txbuf->m_head != NULL) { + bus_dmamap_unload(txr->tx_tag, txbuf->map); + m_freem(txbuf->m_head); + txbuf->m_head = NULL; + } + } +} + +static void +ix_free_rx_ring(struct ix_rx_ring *rxr) +{ + int i; + + for (i = 0; i < rxr->rx_ndesc; ++i) { + struct ix_rx_buf *rxbuf = &rxr->rx_buf[i]; + + if (rxbuf->fmp != NULL) { + m_freem(rxbuf->fmp); + rxbuf->fmp = NULL; + rxbuf->lmp = NULL; + } else { + KKASSERT(rxbuf->lmp == NULL); + } + if (rxbuf->m_head != NULL) { + bus_dmamap_unload(rxr->rx_tag, rxbuf->map); + m_freem(rxbuf->m_head); + rxbuf->m_head = NULL; + } + } +} + +static int +ix_newbuf(struct ix_rx_ring *rxr, int i, boolean_t wait) +{ + struct mbuf *m; + bus_dma_segment_t seg; + bus_dmamap_t map; + struct ix_rx_buf *rxbuf; + int flags, error, nseg; + + flags = MB_DONTWAIT; + if (__predict_false(wait)) + flags = MB_WAIT; + + m = m_getjcl(flags, MT_DATA, M_PKTHDR, rxr->rx_mbuf_sz); + if (m == NULL) { + if (wait) { + if_printf(&rxr->rx_sc->arpcom.ac_if, + "Unable to allocate RX mbuf\n"); + } + return ENOBUFS; + } + m->m_len = m->m_pkthdr.len = rxr->rx_mbuf_sz; + + error = bus_dmamap_load_mbuf_segment(rxr->rx_tag, + rxr->rx_sparemap, m, &seg, 1, &nseg, BUS_DMA_NOWAIT); + if (error) { + m_freem(m); + if (wait) { + if_printf(&rxr->rx_sc->arpcom.ac_if, + "Unable to load RX mbuf\n"); + } + return error; + } + + rxbuf = &rxr->rx_buf[i]; + if (rxbuf->m_head != NULL) + bus_dmamap_unload(rxr->rx_tag, rxbuf->map); + + map = rxbuf->map; + rxbuf->map = rxr->rx_sparemap; + rxr->rx_sparemap = map; + + rxbuf->m_head = m; + rxbuf->paddr = seg.ds_addr; + + ix_setup_rxdesc(&rxr->rx_base[i], rxbuf); + return 0; +} + +static void +ix_add_sysctl(struct ix_softc *sc) +{ +#ifdef IX_RSS_DEBUG + char node[32]; +#endif + int i, add; + + sysctl_ctx_init(&sc->sysctl_ctx); + sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, + device_get_nameunit(sc->dev), CTLFLAG_RD, 0, ""); + if (sc->sysctl_tree == NULL) { + device_printf(sc->dev, "can't add sysctl node\n"); + return; + } + + SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "rxr", CTLFLAG_RD, &sc->rx_ring_cnt, 0, "# of RX rings"); + SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "rxr_inuse", CTLFLAG_RD, &sc->rx_ring_inuse, 0, + "# of RX rings used"); + SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "txr", CTLFLAG_RD, &sc->tx_ring_cnt, 0, "# of TX rings"); + SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "txr_inuse", CTLFLAG_RD, &sc->tx_ring_inuse, 0, + "# of TX rings used"); + SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "rxd", CTLTYPE_INT | CTLFLAG_RD, + sc, 0, ix_sysctl_rxd, "I", + "# of RX descs"); + SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "txd", CTLTYPE_INT | CTLFLAG_RD, + sc, 0, ix_sysctl_txd, "I", + "# of TX descs"); + SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "tx_wreg_nsegs", CTLTYPE_INT | CTLFLAG_RW, + sc, 0, ix_sysctl_tx_wreg_nsegs, "I", + "# of segments sent before write to hardware register"); + SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "rx_wreg_nsegs", CTLTYPE_INT | CTLFLAG_RW, + sc, 0, ix_sysctl_rx_wreg_nsegs, "I", + "# of received segments sent before write to hardware register"); + SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "tx_intr_nsegs", CTLTYPE_INT | CTLFLAG_RW, + sc, 0, ix_sysctl_tx_intr_nsegs, "I", + "# of segments per TX interrupt"); + + add = 0; + for (i = 0; i < sc->intr_cnt; ++i) { + if (sc->intr_data[i].intr_use == IX_INTR_USE_RXTX) { + add = 1; + break; + } + } + if (add) { + SYSCTL_ADD_PROC(&sc->sysctl_ctx, + SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "intr_rate", CTLTYPE_INT | CTLFLAG_RW, + sc, 0, ix_sysctl_intr_rate, "I", + "interrupt rate"); + } + +#ifdef IX_RSS_DEBUG + SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "rss_debug", CTLFLAG_RW, &sc->rss_debug, 0, + "RSS debug level"); + for (i = 0; i < sc->rx_ring_cnt; ++i) { + ksnprintf(node, sizeof(node), "rx%d_pkt", i); + SYSCTL_ADD_ULONG(&sc->sysctl_ctx, + SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, node, + CTLFLAG_RW, &sc->rx_rings[i].rx_pkts, "RXed packets"); + } +#endif + + SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "flowctrl", CTLTYPE_INT | CTLFLAG_RW, + sc, 0, ix_sysctl_flowctrl, "I", + "flow control, 0 - off, 1 - rx pause, 2 - tx pause, 3 - full"); + +#ifdef foo + /* + * Allow a kind of speed control by forcing the autoneg + * advertised speed list to only a certain value, this + * supports 1G on 82599 devices, and 100Mb on X540. + */ + SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree), + OID_AUTO, "advspeed", CTLTYPE_INT | CTLFLAG_RW, + sc, 0, ix_sysctl_advspeed, "I", + "advertised link speed, " + "0 - auto, 1 - 1Gb, 2 - 100Mb, 3 - 1Gb/10Gb"); +#endif + +#if 0 + ix_add_hw_stats(sc); +#endif + +} + +static int +ix_sysctl_tx_wreg_nsegs(SYSCTL_HANDLER_ARGS) +{ + struct ix_softc *sc = (void *)arg1; + struct ifnet *ifp = &sc->arpcom.ac_if; + int error, nsegs, i; + + nsegs = sc->tx_rings[0].tx_wreg_nsegs; + error = sysctl_handle_int(oidp, &nsegs, 0, req); + if (error || req->newptr == NULL) + return error; + if (nsegs < 0) + return EINVAL; + + ifnet_serialize_all(ifp); + for (i = 0; i < sc->tx_ring_cnt; ++i) + sc->tx_rings[i].tx_wreg_nsegs = nsegs; + ifnet_deserialize_all(ifp); + + return 0; +} + +static int +ix_sysctl_rx_wreg_nsegs(SYSCTL_HANDLER_ARGS) +{ + struct ix_softc *sc = (void *)arg1; + struct ifnet *ifp = &sc->arpcom.ac_if; + int error, nsegs, i; + + nsegs = sc->rx_rings[0].rx_wreg_nsegs; + error = sysctl_handle_int(oidp, &nsegs, 0, req); + if (error || req->newptr == NULL) + return error; + if (nsegs < 0) + return EINVAL; + + ifnet_serialize_all(ifp); + for (i = 0; i < sc->rx_ring_cnt; ++i) + sc->rx_rings[i].rx_wreg_nsegs =nsegs; + ifnet_deserialize_all(ifp); + + return 0; +} + +static int +ix_sysctl_txd(SYSCTL_HANDLER_ARGS) +{ + struct ix_softc *sc = (void *)arg1; + int txd; + + txd = sc->tx_rings[0].tx_ndesc; + return sysctl_handle_int(oidp, &txd, 0, req); +} + +static int +ix_sysctl_rxd(SYSCTL_HANDLER_ARGS) +{ + struct ix_softc *sc = (void *)arg1; + int rxd; + + rxd = sc->rx_rings[0].rx_ndesc; + return sysctl_handle_int(oidp, &rxd, 0, req); +} + +static int +ix_sysctl_tx_intr_nsegs(SYSCTL_HANDLER_ARGS) +{ + struct ix_softc *sc = (void *)arg1; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct ix_tx_ring *txr = &sc->tx_rings[0]; + int error, nsegs; + + nsegs = txr->tx_intr_nsegs; + error = sysctl_handle_int(oidp, &nsegs, 0, req); + if (error || req->newptr == NULL) + return error; + if (nsegs < 0) + return EINVAL; + + ifnet_serialize_all(ifp); + + if (nsegs >= txr->tx_ndesc - IX_MAX_SCATTER - IX_TX_RESERVED) { + error = EINVAL; + } else { + int i; + + error = 0; + for (i = 0; i < sc->tx_ring_cnt; ++i) + sc->tx_rings[i].tx_intr_nsegs = nsegs; + } + + ifnet_deserialize_all(ifp); + + return error; +} + +static void +ix_set_eitr(struct ix_softc *sc, int idx, int rate) +{ + uint32_t eitr, eitr_intvl; + + eitr = IXGBE_READ_REG(&sc->hw, IXGBE_EITR(idx)); + eitr_intvl = 1000000000 / 256 / rate; + + if (sc->hw.mac.type == ixgbe_mac_82598EB) { + eitr &= ~IX_EITR_INTVL_MASK_82598; + if (eitr_intvl == 0) + eitr_intvl = 1; + else if (eitr_intvl > IX_EITR_INTVL_MASK_82598) + eitr_intvl = IX_EITR_INTVL_MASK_82598; + } else { + eitr &= ~IX_EITR_INTVL_MASK; + + eitr_intvl &= ~IX_EITR_INTVL_RSVD_MASK; + if (eitr_intvl == 0) + eitr_intvl = IX_EITR_INTVL_MIN; + else if (eitr_intvl > IX_EITR_INTVL_MAX) + eitr_intvl = IX_EITR_INTVL_MAX; + } + eitr |= eitr_intvl; + + IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(idx), eitr); +} + +static int +ix_sysctl_intr_rate(SYSCTL_HANDLER_ARGS) +{ + struct ix_softc *sc = (void *)arg1; + struct ifnet *ifp = &sc->arpcom.ac_if; + int error, rate, i; + + rate = 0; + for (i = 0; i < sc->intr_cnt; ++i) { + if (sc->intr_data[i].intr_use == IX_INTR_USE_RXTX) { + rate = sc->intr_data[i].intr_rate; + break; + } + } + + error = sysctl_handle_int(oidp, &rate, 0, req); + if (error || req->newptr == NULL) + return error; + if (rate <= 0) + return EINVAL; + + ifnet_serialize_all(ifp); + + for (i = 0; i < sc->intr_cnt; ++i) { + if (sc->intr_data[i].intr_use == IX_INTR_USE_RXTX) { + sc->intr_data[i].intr_rate = rate; + if (ifp->if_flags & IFF_RUNNING) + ix_set_eitr(sc, i, rate); + } + } + + ifnet_deserialize_all(ifp); + + return error; +} + +static void +ix_set_timer_cpuid(struct ix_softc *sc, boolean_t polling) +{ + if (polling || sc->intr_type == PCI_INTR_TYPE_MSIX) + sc->timer_cpuid = 0; /* XXX fixed */ + else + sc->timer_cpuid = rman_get_cpuid(sc->intr_data[0].intr_res); +} diff --git a/sys/dev/netif/ix/if_ix.h b/sys/dev/netif/ix/if_ix.h new file mode 100644 index 0000000000..c12fda9123 --- /dev/null +++ b/sys/dev/netif/ix/if_ix.h @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2001-2013, 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. + */ + +#ifndef _IF_IX_H_ +#define _IF_IX_H_ + +/* Tunables */ + +/* + * RX ring count + */ +#define IX_MAX_RXRING 16 +#define IX_MIN_RXRING_RSS 2 + +/* + * Default number of segments received before writing to RX related registers + */ +#define IX_DEF_RXWREG_NSEGS 32 + +/* + * Default number of segments sent before writing to TX related registers + */ +#define IX_DEF_TXWREG_NSEGS 8 + +/* + * 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 IX_DEF_TXD 1024 +#define IX_PERF_TXD 2048 +#define IX_MAX_TXD 4096 +#define IX_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 IX_DEF_RXD 1024 +#define IX_PERF_RXD 2048 +#define IX_MAX_RXD 4096 +#define IX_MIN_RXD 64 + +/* Alignment for rings */ +#define IX_DBA_ALIGN 128 + +#define IX_MAX_FRAME_SIZE 0x3F00 + +/* Flow control constants */ +#define IX_FC_PAUSE 0xFFFF +#define IX_FC_HI 0x20000 +#define IX_FC_LO 0x10000 + +/* + * RSS related registers + */ +#define IX_NRSSRK 10 +#define IX_RSSRK_SIZE 4 +#define IX_RSSRK_VAL(key, i) (key[(i) * IX_RSSRK_SIZE] | \ + key[(i) * IX_RSSRK_SIZE + 1] << 8 | \ + key[(i) * IX_RSSRK_SIZE + 2] << 16 | \ + key[(i) * IX_RSSRK_SIZE + 3] << 24) +#define IX_NRETA 32 +#define IX_RETA_SIZE 4 + +/* + * EITR + */ +#define IX_EITR_INTVL_MASK_82598 0xffff +#define IX_EITR_INTVL_MASK 0x0fff +#define IX_EITR_INTVL_RSVD_MASK 0x0007 +#define IX_EITR_INTVL_MIN IXGBE_MIN_EITR +#define IX_EITR_INTVL_MAX IXGBE_MAX_EITR + +/* + * Used for optimizing small rx mbufs. Effort is made to keep the copy + * small and aligned for the CPU L1 cache. + * + * MHLEN is typically 168 bytes, giving us 8-byte alignment. Getting + * 32 byte alignment needed for the fast bcopy results in 8 bytes being + * wasted. Getting 64 byte alignment, which _should_ be ideal for + * modern Intel CPUs, results in 40 bytes wasted and a significant drop + * in observed efficiency of the optimization, 97.9% -> 81.8%. + */ +#define IX_RX_COPY_LEN 160 +#define IX_RX_COPY_ALIGN (MHLEN - IX_RX_COPY_LEN) + +#define IX_MAX_MCASTADDR 128 + +#define MSIX_82598_BAR 3 +#define MSIX_82599_BAR 4 + +#define IX_TSO_SIZE (IP_MAXPACKET + \ + sizeof(struct ether_vlan_header)) + +/* + * MUST be less than 38. Though 82598 does not have this limit, + * we don't want long TX chain. 33 should be large enough even + * for 64K TSO (32 x 2K mbuf cluster and 1 x mbuf header). + * + * Reference: + * - 82599 datasheet 7.2.1.1 + * - X540 datasheet 7.2.1.1 + */ +#define IX_MAX_SCATTER 33 +#define IX_TX_RESERVED 3 /* 1 for TX ctx, 2 reserved */ + +/* MSI and legacy interrupt */ +#define IX_TX_INTR_VEC 0 +#define IX_TX_INTR_MASK (1 << IX_TX_INTR_VEC) +#define IX_RX0_INTR_VEC 1 +#define IX_RX0_INTR_MASK (1 << IX_RX0_INTR_VEC) +#define IX_RX1_INTR_VEC 2 +#define IX_RX1_INTR_MASK (1 << IX_RX1_INTR_VEC) + +#define IX_INTR_RATE 8000 + +/* IOCTL define to gather SFP+ Diagnostic data */ +#define SIOCGI2C SIOCGIFGENERIC + +/* TX checksum offload */ +#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP) + +/* This is used to get SFP+ module data */ +struct ix_i2c_req { + uint8_t dev_addr; + uint8_t offset; + uint8_t len; + uint8_t data[8]; +}; + +struct ix_tx_buf { + struct mbuf *m_head; + bus_dmamap_t map; +}; + +struct ix_rx_buf { + struct mbuf *m_head; + struct mbuf *fmp; + struct mbuf *lmp; + bus_dmamap_t map; + bus_addr_t paddr; + u_int flags; +#define IX_RX_COPY 0x1 +}; + +struct ix_softc; + +struct ix_tx_ring { + struct lwkt_serialize tx_serialize; + struct ifaltq_subque *tx_ifsq; + struct ix_softc *tx_sc; + volatile uint32_t *tx_hdr; + union ixgbe_adv_tx_desc *tx_base; + struct ix_tx_buf *tx_buf; + bus_dma_tag_t tx_tag; + uint32_t tx_idx; + uint16_t tx_avail; + uint16_t tx_next_avail; + uint16_t tx_next_clean; + uint16_t tx_ndesc; + uint16_t tx_wreg_nsegs; + uint16_t tx_intr_nsegs; + uint16_t tx_nsegs; + int16_t tx_intr_vec; + int tx_intr_cpuid; + struct ifsubq_watchdog tx_watchdog; + + bus_dma_tag_t tx_base_dtag; + bus_dmamap_t tx_base_map; + bus_addr_t tx_base_paddr; + + bus_dma_tag_t tx_hdr_dtag; + bus_dmamap_t tx_hdr_map; + bus_addr_t tx_hdr_paddr; +} __cachealign; + +struct ix_rx_ring { + struct lwkt_serialize rx_serialize; + struct ix_softc *rx_sc; + union ixgbe_adv_rx_desc *rx_base; + struct ix_rx_buf *rx_buf; + bus_dma_tag_t rx_tag; + bus_dmamap_t rx_sparemap; + uint32_t rx_idx; + uint16_t rx_flags; +#define IX_RXRING_FLAG_LRO 0x01 +#define IX_RXRING_FLAG_DISC 0x02 + uint16_t rx_next_check; + uint16_t rx_ndesc; + uint16_t rx_mbuf_sz; + uint16_t rx_wreg_nsegs; + int16_t rx_intr_vec; + +#ifdef IX_RSS_DEBUG + u_long rx_pkts; +#endif + + bus_dma_tag_t rx_base_dtag; + bus_dmamap_t rx_base_map; + bus_addr_t rx_base_paddr; +} __cachealign; + +struct ix_intr_data { + struct lwkt_serialize *intr_serialize; + driver_intr_t *intr_func; + void *intr_hand; + struct resource *intr_res; + void *intr_funcarg; + int intr_rid; + int intr_cpuid; + int intr_rate; + int intr_use; +#define IX_INTR_USE_RXTX 0 +#define IX_INTR_USE_STATUS 1 +#define IX_INTR_USE_RX 2 +#define IX_INTR_USE_TX 3 + const char *intr_desc; + char intr_desc0[64]; +}; + +struct ix_softc { + struct arpcom arpcom; + + struct ixgbe_hw hw; + struct ixgbe_osdep osdep; + + struct lwkt_serialize main_serialize; + uint32_t intr_mask; + + boolean_t link_active; + + int tx_ring_cnt; + int tx_ring_inuse; + struct ix_tx_ring *tx_rings; + + int rx_ring_cnt; + int rx_ring_inuse; + struct ix_rx_ring *rx_rings; + + struct callout timer; + int timer_cpuid; + + uint32_t optics; + uint32_t fc; /* local flow ctrl setting */ + uint32_t link_speed; + bool link_up; + boolean_t sfp_probe; /* plyggable optics */ + + struct ixgbe_hw_stats stats; + + int intr_type; + int intr_cnt; + struct ix_intr_data *intr_data; + + /* sysctl tree glue */ + struct sysctl_ctx_list sysctl_ctx; + struct sysctl_oid *sysctl_tree; + + device_t dev; + bus_dma_tag_t parent_tag; + struct ifmedia media; + + struct resource *mem_res; + int mem_rid; + + int nserialize; + struct lwkt_serialize **serializes; + + uint8_t *mta; /* Multicast array memory */ + + int if_flags; + int advspeed; /* advertised link speeds */ + uint16_t max_frame_size; + +#ifdef IX_RSS_DEBUG + int rss_debug; +#endif +}; + +#define IX_ENABLE_HWRSS(sc) ((sc)->rx_ring_cnt > 1) +#define IX_ENABLE_HWTSS(sc) ((sc)->tx_ring_cnt > 1) + +#endif /* _IF_IX_H_ */ diff --git a/sys/dev/netif/ixgbe/ixgbe_82598.c b/sys/dev/netif/ix/ixgbe_82598.c similarity index 94% rename from sys/dev/netif/ixgbe/ixgbe_82598.c rename to sys/dev/netif/ix/ixgbe_82598.c index 15ece965d6..e32f2700fe 100644 --- a/sys/dev/netif/ixgbe/ixgbe_82598.c +++ b/sys/dev/netif/ix/ixgbe_82598.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_82598.c,v 1.13 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #include "ixgbe_type.h" #include "ixgbe_82598.h" @@ -49,18 +49,17 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, bool link_up_wait_to_complete); static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete); static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete); static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw); static s32 ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq); static s32 ixgbe_clear_vfta_82598(struct ixgbe_hw *hw); static void ixgbe_set_rxpba_82598(struct ixgbe_hw *hw, int num_pb, u32 headroom, int strategy); - +static s32 ixgbe_read_i2c_sff8472_82598(struct ixgbe_hw *hw, u8 byte_offset, + u8 *sff8472_data); /** * ixgbe_set_pcie_completion_timeout - set pci-e completion timeout * @hw: pointer to the HW structure @@ -155,6 +154,7 @@ s32 ixgbe_init_ops_82598(struct ixgbe_hw *hw) /* SFP+ Module */ phy->ops.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_82598; + phy->ops.read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_82598; /* Link */ mac->ops.check_link = &ixgbe_check_mac_link_82598; @@ -166,6 +166,8 @@ s32 ixgbe_init_ops_82598(struct ixgbe_hw *hw) /* Manageability interface */ mac->ops.set_fw_drv_ver = NULL; + mac->ops.get_rtrup2tc = NULL; + return ret_val; } @@ -712,15 +714,15 @@ out: * ixgbe_setup_mac_link_82598 - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed - * @autoneg: TRUE if autonegotiation enabled * @autoneg_wait_to_complete: TRUE when waiting for completion is needed * * Set the link speed in the AUTOC register and restarts link. **/ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, + ixgbe_link_speed speed, bool autoneg_wait_to_complete) { + bool autoneg = FALSE; s32 status = IXGBE_SUCCESS; ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN; u32 curr_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); @@ -766,14 +768,12 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw, * ixgbe_setup_copper_link_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. **/ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete) { s32 status; @@ -781,7 +781,7 @@ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw, DEBUGFUNC("ixgbe_setup_copper_link_82598"); /* Setup the PHY according to input speed */ - status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, + status = hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait_to_complete); /* Set up MAC */ ixgbe_start_mac_link_82598(hw, autoneg_wait_to_complete); @@ -1102,23 +1102,33 @@ s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) } /** - * ixgbe_read_i2c_eeprom_82598 - Reads 8 bit word over I2C interface. + * ixgbe_read_i2c_phy_82598 - Reads 8 bit word over I2C interface. * @hw: pointer to hardware structure - * @byte_offset: EEPROM byte offset to read + * @dev_addr: address to read from + * @byte_offset: byte offset to read from dev_addr * @eeprom_data: value read * * Performs 8 byte read operation to SFP module's EEPROM over I2C interface. **/ -s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, - u8 *eeprom_data) +static s32 ixgbe_read_i2c_phy_82598(struct ixgbe_hw *hw, u8 dev_addr, + u8 byte_offset, u8 *eeprom_data) { s32 status = IXGBE_SUCCESS; u16 sfp_addr = 0; u16 sfp_data = 0; u16 sfp_stat = 0; + u16 gssr; u32 i; - DEBUGFUNC("ixgbe_read_i2c_eeprom_82598"); + DEBUGFUNC("ixgbe_read_i2c_phy_82598"); + + if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) + gssr = IXGBE_GSSR_PHY1_SM; + else + gssr = IXGBE_GSSR_PHY0_SM; + + if (hw->mac.ops.acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS) + return IXGBE_ERR_SWFW_SYNC; if (hw->phy.type == ixgbe_phy_nl) { /* @@ -1126,19 +1136,19 @@ s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, * 0xC30D. These registers are used to talk to the SFP+ * module's EEPROM through the SDA/SCL (I2C) interface. */ - sfp_addr = (IXGBE_I2C_EEPROM_DEV_ADDR << 8) + byte_offset; + sfp_addr = (dev_addr << 8) + byte_offset; sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK); - hw->phy.ops.write_reg(hw, - IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, - sfp_addr); + hw->phy.ops.write_reg_mdi(hw, + IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + sfp_addr); /* Poll status */ for (i = 0; i < 100; i++) { - hw->phy.ops.read_reg(hw, - IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, - &sfp_stat); + hw->phy.ops.read_reg_mdi(hw, + IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &sfp_stat); sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) break; @@ -1152,19 +1162,49 @@ s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, } /* Read data */ - hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA, - IXGBE_MDIO_PMA_PMD_DEV_TYPE, &sfp_data); + hw->phy.ops.read_reg_mdi(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &sfp_data); *eeprom_data = (u8)(sfp_data >> 8); } else { status = IXGBE_ERR_PHY; - goto out; } out: + hw->mac.ops.release_swfw_sync(hw, gssr); return status; } +/** + * ixgbe_read_i2c_eeprom_82598 - Reads 8 bit word over I2C interface. + * @hw: pointer to hardware structure + * @byte_offset: EEPROM byte offset to read + * @eeprom_data: value read + * + * Performs 8 byte read operation to SFP module's EEPROM over I2C interface. + **/ +s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, + u8 *eeprom_data) +{ + return ixgbe_read_i2c_phy_82598(hw, IXGBE_I2C_EEPROM_DEV_ADDR, + byte_offset, eeprom_data); +} + +/** + * ixgbe_read_i2c_sff8472_82598 - Reads 8 bit word over I2C interface. + * @hw: pointer to hardware structure + * @byte_offset: byte offset at address 0xA2 + * @eeprom_data: value read + * + * Performs 8 byte read operation to SFP module's SFF-8472 data over I2C + **/ +static s32 ixgbe_read_i2c_sff8472_82598(struct ixgbe_hw *hw, u8 byte_offset, + u8 *sff8472_data) +{ + return ixgbe_read_i2c_phy_82598(hw, IXGBE_I2C_EEPROM_DEV_ADDR2, + byte_offset, sff8472_data); +} + /** * ixgbe_get_supported_physical_layer_82598 - Returns physical layer type * @hw: pointer to hardware structure diff --git a/sys/dev/netif/ixgbe/ixgbe_82598.h b/sys/dev/netif/ix/ixgbe_82598.h similarity index 95% rename from sys/dev/netif/ixgbe/ixgbe_82598.h rename to sys/dev/netif/ix/ixgbe_82598.h index 734e8fbe8b..16cd2eeee0 100644 --- a/sys/dev/netif/ixgbe/ixgbe_82598.h +++ b/sys/dev/netif/ix/ixgbe_82598.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_82598.h,v 1.2 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef _IXGBE_82598_H_ #define _IXGBE_82598_H_ diff --git a/sys/dev/netif/ixgbe/ixgbe_82599.c b/sys/dev/netif/ix/ixgbe_82599.c similarity index 85% rename from sys/dev/netif/ixgbe/ixgbe_82599.c rename to sys/dev/netif/ix/ixgbe_82599.c index 5232a2ad6a..3cc8cd7cda 100644 --- a/sys/dev/netif/ixgbe/ixgbe_82599.c +++ b/sys/dev/netif/ix/ixgbe_82599.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_82599.c,v 1.8 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #include "ixgbe_type.h" #include "ixgbe_82599.h" @@ -40,7 +40,6 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete); static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, @@ -48,14 +47,37 @@ static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, static s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset, u16 words, u16 *data); +static bool ixgbe_mng_enabled(struct ixgbe_hw *hw) +{ + u32 fwsm, manc, factps; + + fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM); + if ((fwsm & IXGBE_FWSM_MODE_MASK) != IXGBE_FWSM_FW_MODE_PT) + return FALSE; + + manc = IXGBE_READ_REG(hw, IXGBE_MANC); + if (!(manc & IXGBE_MANC_RCV_TCO_EN)) + return FALSE; + + factps = IXGBE_READ_REG(hw, IXGBE_FACTPS); + if (factps & IXGBE_FACTPS_MNGCG) + return FALSE; + + return TRUE; +} + void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; DEBUGFUNC("ixgbe_init_mac_link_ops_82599"); - /* enable the laser control functions for SFP+ fiber */ - if (mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) { + /* + * enable the laser control functions for SFP+ fiber + * and MNG not enabled + */ + if ((mac->ops.get_media_type(hw) == ixgbe_media_type_fiber) && + !hw->mng_fw_enabled) { mac->ops.disable_tx_laser = &ixgbe_disable_tx_laser_multispeed_fiber; mac->ops.enable_tx_laser = @@ -135,9 +157,8 @@ init_phy_ops_out: s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) { s32 ret_val = IXGBE_SUCCESS; - u32 reg_anlp1 = 0; - u32 i = 0; u16 list_offset, data_offset, data_value; + bool got_lock = FALSE; DEBUGFUNC("ixgbe_setup_sfp_modules_82599"); @@ -159,11 +180,13 @@ s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) goto setup_sfp_out; } - hw->eeprom.ops.read(hw, ++data_offset, &data_value); + if (hw->eeprom.ops.read(hw, ++data_offset, &data_value)) + goto setup_sfp_err; while (data_value != 0xffff) { IXGBE_WRITE_REG(hw, IXGBE_CORECTL, data_value); IXGBE_WRITE_FLUSH(hw); - hw->eeprom.ops.read(hw, ++data_offset, &data_value); + if (hw->eeprom.ops.read(hw, ++data_offset, &data_value)) + goto setup_sfp_err; } /* Release the semaphore */ @@ -171,32 +194,52 @@ s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) /* Delay obtaining semaphore again to allow FW access */ msec_delay(hw->eeprom.semaphore_delay); - /* Now restart DSP by setting Restart_AN and clearing LMS */ - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((IXGBE_READ_REG(hw, - IXGBE_AUTOC) & ~IXGBE_AUTOC_LMS_MASK) | - IXGBE_AUTOC_AN_RESTART)); - - /* Wait for AN to leave state 0 */ - for (i = 0; i < 10; i++) { - msec_delay(4); - reg_anlp1 = IXGBE_READ_REG(hw, IXGBE_ANLP1); - if (reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK) - break; + /* Need SW/FW semaphore around AUTOC writes if LESM on, + * likewise reset_pipeline requires lock as it also writes + * AUTOC. + */ + if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (ret_val != IXGBE_SUCCESS) { + ret_val = IXGBE_ERR_SWFW_SYNC; + goto setup_sfp_out; + } + + got_lock = TRUE; } - if (!(reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK)) { + + /* Restart DSP and set SFI mode */ + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((hw->mac.orig_autoc) | + IXGBE_AUTOC_LMS_10G_SERIAL)); + hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + ret_val = ixgbe_reset_pipeline_82599(hw); + + if (got_lock) { + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + got_lock = FALSE; + } + + if (ret_val) { DEBUGOUT("sfp module setup not complete\n"); ret_val = IXGBE_ERR_SFP_SETUP_NOT_COMPLETE; goto setup_sfp_out; } - /* Restart DSP by setting Restart_AN and return to SFI mode */ - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (IXGBE_READ_REG(hw, - IXGBE_AUTOC) | IXGBE_AUTOC_LMS_10G_SERIAL | - IXGBE_AUTOC_AN_RESTART)); } setup_sfp_out: return ret_val; + +setup_sfp_err: + /* Release the semaphore */ + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + /* Delay obtaining semaphore again to allow FW access */ + msec_delay(hw->eeprom.semaphore_delay); + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", data_offset); + return IXGBE_ERR_PHY; } /** @@ -216,7 +259,7 @@ s32 ixgbe_init_ops_82599(struct ixgbe_hw *hw) DEBUGFUNC("ixgbe_init_ops_82599"); - ret_val = ixgbe_init_phy_ops_generic(hw); + ixgbe_init_phy_ops_generic(hw); ret_val = ixgbe_init_ops_generic(hw); /* PHY */ @@ -282,6 +325,11 @@ s32 ixgbe_init_ops_82599(struct ixgbe_hw *hw) mac->ops.set_fw_drv_ver = &ixgbe_set_fw_drv_ver_generic; + mac->ops.get_rtrup2tc = &ixgbe_dcb_get_rtrup2tc_generic; + + /* Cache if MNG FW is up */ + hw->mng_fw_enabled = ixgbe_mng_enabled(hw); + return ret_val; } @@ -289,13 +337,13 @@ s32 ixgbe_init_ops_82599(struct ixgbe_hw *hw) * ixgbe_get_link_capabilities_82599 - Determines link capabilities * @hw: pointer to hardware structure * @speed: pointer to link speed - * @negotiation: TRUE when autoneg or autotry is enabled + * @autoneg: TRUE when autoneg or autotry is enabled * * Determines the link capabilities by reading the AUTOC register. **/ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed, - bool *negotiation) + bool *autoneg) { s32 status = IXGBE_SUCCESS; u32 autoc = 0; @@ -309,7 +357,7 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1) { *speed = IXGBE_LINK_SPEED_1GB_FULL; - *negotiation = TRUE; + *autoneg = TRUE; goto out; } @@ -326,22 +374,22 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, switch (autoc & IXGBE_AUTOC_LMS_MASK) { case IXGBE_AUTOC_LMS_1G_LINK_NO_AN: *speed = IXGBE_LINK_SPEED_1GB_FULL; - *negotiation = FALSE; + *autoneg = FALSE; break; case IXGBE_AUTOC_LMS_10G_LINK_NO_AN: *speed = IXGBE_LINK_SPEED_10GB_FULL; - *negotiation = FALSE; + *autoneg = FALSE; break; case IXGBE_AUTOC_LMS_1G_AN: *speed = IXGBE_LINK_SPEED_1GB_FULL; - *negotiation = TRUE; + *autoneg = TRUE; break; case IXGBE_AUTOC_LMS_10G_SERIAL: *speed = IXGBE_LINK_SPEED_10GB_FULL; - *negotiation = FALSE; + *autoneg = FALSE; break; case IXGBE_AUTOC_LMS_KX4_KX_KR: @@ -353,7 +401,7 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, *speed |= IXGBE_LINK_SPEED_10GB_FULL; if (autoc & IXGBE_AUTOC_KX_SUPP) *speed |= IXGBE_LINK_SPEED_1GB_FULL; - *negotiation = TRUE; + *autoneg = TRUE; break; case IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII: @@ -364,12 +412,12 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, *speed |= IXGBE_LINK_SPEED_10GB_FULL; if (autoc & IXGBE_AUTOC_KX_SUPP) *speed |= IXGBE_LINK_SPEED_1GB_FULL; - *negotiation = TRUE; + *autoneg = TRUE; break; case IXGBE_AUTOC_LMS_SGMII_1G_100M: *speed = IXGBE_LINK_SPEED_1GB_FULL | IXGBE_LINK_SPEED_100_FULL; - *negotiation = FALSE; + *autoneg = FALSE; break; default: @@ -381,7 +429,7 @@ s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw, if (hw->phy.multispeed_fiber) { *speed |= IXGBE_LINK_SPEED_10GB_FULL | IXGBE_LINK_SPEED_1GB_FULL; - *negotiation = TRUE; + *autoneg = TRUE; } out: @@ -424,6 +472,7 @@ enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82599_SFP_FCOE: case IXGBE_DEV_ID_82599_SFP_EM: case IXGBE_DEV_ID_82599_SFP_SF2: + case IXGBE_DEV_ID_82599_SFP_SF_QP: case IXGBE_DEV_ID_82599EN_SFP: media_type = ixgbe_media_type_fiber; break; @@ -433,6 +482,10 @@ enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82599_T3_LOM: media_type = ixgbe_media_type_copper; break; + case IXGBE_DEV_ID_82599_BYPASS: + media_type = ixgbe_media_type_fiber_fixed; + hw->phy.multispeed_fiber = TRUE; + break; default: media_type = ixgbe_media_type_unknown; break; @@ -441,6 +494,29 @@ out: return media_type; } +/** + * ixgbe_stop_mac_link_on_d3_82599 - Disables link on D3 + * @hw: pointer to hardware structure + * + * Disables link during D3 power down sequence. + * + **/ +void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw) +{ + u32 autoc2_reg; + u16 ee_ctrl_2 = 0; + + DEBUGFUNC("ixgbe_stop_mac_link_on_d3_82599"); + ixgbe_read_eeprom(hw, IXGBE_EEPROM_CTRL_2, &ee_ctrl_2); + + if (!hw->mng_fw_enabled && !hw->wol_enabled && + ee_ctrl_2 & IXGBE_EEPROM_CCD_BIT) { + autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + autoc2_reg |= IXGBE_AUTOC2_LINK_DISABLE_ON_D3_MASK; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2_reg); + } +} + /** * ixgbe_start_mac_link_82599 - Setup MAC link settings * @hw: pointer to hardware structure @@ -456,17 +532,32 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, u32 links_reg; u32 i; s32 status = IXGBE_SUCCESS; + bool got_lock = FALSE; DEBUGFUNC("ixgbe_start_mac_link_82599"); + /* reset_pipeline requires us to hold this lock as it writes to + * AUTOC. + */ + if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { + status = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (status != IXGBE_SUCCESS) + goto out; + + got_lock = TRUE; + } + /* Restart link */ - autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); - autoc_reg |= IXGBE_AUTOC_AN_RESTART; - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); /* Only poll for autoneg to complete if specified to do so */ if (autoneg_wait_to_complete) { + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) == IXGBE_AUTOC_LMS_KX4_KX_KR || (autoc_reg & IXGBE_AUTOC_LMS_MASK) == @@ -490,6 +581,7 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, /* Add delay to filter out noises during initial link setup */ msec_delay(50); +out: return status; } @@ -554,17 +646,85 @@ void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) } } +/** + * ixgbe_set_fiber_fixed_speed - Set module link speed for fixed fiber + * @hw: pointer to hardware structure + * @speed: link speed to set + * + * We set the module speed differently for fixed fiber. For other + * multi-speed devices we don't have an error value so here if we + * detect an error we just log it and exit. + */ +static void ixgbe_set_fiber_fixed_speed(struct ixgbe_hw *hw, + ixgbe_link_speed speed) +{ + s32 status; + u8 rs, eeprom_data; + + switch (speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + /* one bit mask same as setting on */ + rs = IXGBE_SFF_SOFT_RS_SELECT_10G; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + rs = IXGBE_SFF_SOFT_RS_SELECT_1G; + break; + default: + DEBUGOUT("Invalid fixed module speed\n"); + return; + } + + /* Set RS0 */ + status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB, + IXGBE_I2C_EEPROM_DEV_ADDR2, + &eeprom_data); + if (status) { + DEBUGOUT("Failed to read Rx Rate Select RS0\n"); + goto out; + } + + eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs; + + status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_OSCB, + IXGBE_I2C_EEPROM_DEV_ADDR2, + eeprom_data); + if (status) { + DEBUGOUT("Failed to write Rx Rate Select RS0\n"); + goto out; + } + + /* Set RS1 */ + status = hw->phy.ops.read_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB, + IXGBE_I2C_EEPROM_DEV_ADDR2, + &eeprom_data); + if (status) { + DEBUGOUT("Failed to read Rx Rate Select RS1\n"); + goto out; + } + + eeprom_data = (eeprom_data & ~IXGBE_SFF_SOFT_RS_SELECT_MASK) & rs; + + status = hw->phy.ops.write_i2c_byte(hw, IXGBE_SFF_SFF_8472_ESCB, + IXGBE_I2C_EEPROM_DEV_ADDR2, + eeprom_data); + if (status) { + DEBUGOUT("Failed to write Rx Rate Select RS1\n"); + goto out; + } +out: + return; +} + /** * ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed - * @autoneg: TRUE if autonegotiation enabled * @autoneg_wait_to_complete: TRUE when waiting for completion is needed * * Set the link speed in the AUTOC register and restarts link. **/ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, + ixgbe_link_speed speed, bool autoneg_wait_to_complete) { s32 status = IXGBE_SUCCESS; @@ -573,13 +733,12 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, u32 speedcnt = 0; u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); u32 i = 0; - bool link_up = FALSE; - bool negotiation; + bool autoneg, link_up = FALSE; DEBUGFUNC("ixgbe_setup_mac_link_multispeed_fiber"); /* Mask off requested but non-supported speeds */ - status = ixgbe_get_link_capabilities(hw, &link_speed, &negotiation); + status = ixgbe_get_link_capabilities(hw, &link_speed, &autoneg); if (status != IXGBE_SUCCESS) return status; @@ -602,16 +761,20 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, goto out; /* Set the module link speed */ - esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5); - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - IXGBE_WRITE_FLUSH(hw); + if (hw->phy.media_type == ixgbe_media_type_fiber_fixed) { + ixgbe_set_fiber_fixed_speed(hw, + IXGBE_LINK_SPEED_10GB_FULL); + } else { + esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5); + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); + } /* Allow module to change analog characteristics (1G->10G) */ msec_delay(40); status = ixgbe_setup_mac_link_82599(hw, IXGBE_LINK_SPEED_10GB_FULL, - autoneg, autoneg_wait_to_complete); if (status != IXGBE_SUCCESS) return status; @@ -653,17 +816,21 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, goto out; /* Set the module link speed */ - esdp_reg &= ~IXGBE_ESDP_SDP5; - esdp_reg |= IXGBE_ESDP_SDP5_DIR; - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - IXGBE_WRITE_FLUSH(hw); + if (hw->phy.media_type == ixgbe_media_type_fiber_fixed) { + ixgbe_set_fiber_fixed_speed(hw, + IXGBE_LINK_SPEED_1GB_FULL); + } else { + esdp_reg &= ~IXGBE_ESDP_SDP5; + esdp_reg |= IXGBE_ESDP_SDP5_DIR; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); + } /* Allow module to change analog characteristics (10G->1G) */ msec_delay(40); status = ixgbe_setup_mac_link_82599(hw, IXGBE_LINK_SPEED_1GB_FULL, - autoneg, autoneg_wait_to_complete); if (status != IXGBE_SUCCESS) return status; @@ -690,7 +857,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, */ if (speedcnt > 1) status = ixgbe_setup_mac_link_multispeed_fiber(hw, - highest_link_speed, autoneg, autoneg_wait_to_complete); + highest_link_speed, autoneg_wait_to_complete); out: /* Set autoneg_advertised value based on input link speed */ @@ -709,13 +876,12 @@ out: * ixgbe_setup_mac_link_smartspeed - Set MAC link speed using SmartSpeed * @hw: pointer to hardware structure * @speed: new link speed - * @autoneg: TRUE if autonegotiation enabled * @autoneg_wait_to_complete: TRUE when waiting for completion is needed * * Implements the Intel SmartSpeed algorithm. **/ s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, + ixgbe_link_speed speed, bool autoneg_wait_to_complete) { s32 status = IXGBE_SUCCESS; @@ -748,7 +914,7 @@ s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, /* First, try to get link with full advertisement */ hw->phy.smart_speed_active = FALSE; for (j = 0; j < IXGBE_SMARTSPEED_MAX_RETRIES; j++) { - status = ixgbe_setup_mac_link_82599(hw, speed, autoneg, + status = ixgbe_setup_mac_link_82599(hw, speed, autoneg_wait_to_complete); if (status != IXGBE_SUCCESS) goto out; @@ -783,7 +949,7 @@ s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, /* Turn SmartSpeed on to disable KR support */ hw->phy.smart_speed_active = TRUE; - status = ixgbe_setup_mac_link_82599(hw, speed, autoneg, + status = ixgbe_setup_mac_link_82599(hw, speed, autoneg_wait_to_complete); if (status != IXGBE_SUCCESS) goto out; @@ -808,7 +974,7 @@ s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, /* We didn't get link. Turn SmartSpeed back off. */ hw->phy.smart_speed_active = FALSE; - status = ixgbe_setup_mac_link_82599(hw, speed, autoneg, + status = ixgbe_setup_mac_link_82599(hw, speed, autoneg_wait_to_complete); out: @@ -822,32 +988,30 @@ out: * ixgbe_setup_mac_link_82599 - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed - * @autoneg: TRUE if autonegotiation enabled * @autoneg_wait_to_complete: TRUE when waiting for completion is needed * * Set the link speed in the AUTOC register and restarts link. **/ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, + ixgbe_link_speed speed, bool autoneg_wait_to_complete) { + bool autoneg = FALSE; s32 status = IXGBE_SUCCESS; - u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 autoc, pma_pmd_1g, link_mode, start_autoc; u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); - u32 start_autoc = autoc; u32 orig_autoc = 0; - u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK; - u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK; u32 links_reg; u32 i; ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN; + bool got_lock = FALSE; DEBUGFUNC("ixgbe_setup_mac_link_82599"); /* Check to see if speed passed in is supported. */ status = ixgbe_get_link_capabilities(hw, &link_capabilities, &autoneg); - if (status != IXGBE_SUCCESS) + if (status) goto out; speed &= link_capabilities; @@ -859,9 +1023,14 @@ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/ if (hw->mac.orig_link_settings_stored) - orig_autoc = hw->mac.orig_autoc; + autoc = hw->mac.orig_autoc; else - orig_autoc = autoc; + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + + orig_autoc = autoc; + start_autoc = hw->mac.cached_autoc; + link_mode = autoc & IXGBE_AUTOC_LMS_MASK; + pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR || link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || @@ -900,9 +1069,31 @@ s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, } if (autoc != start_autoc) { + /* Need SW/FW semaphore around AUTOC writes if LESM is on, + * likewise reset_pipeline requires us to hold this lock as + * it also writes to AUTOC. + */ + if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { + status = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (status != IXGBE_SUCCESS) { + status = IXGBE_ERR_SWFW_SYNC; + goto out; + } + + got_lock = TRUE; + } + /* Restart link */ - autoc |= IXGBE_AUTOC_AN_RESTART; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); + hw->mac.cached_autoc = autoc; + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) { + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + got_lock = FALSE; + } /* Only poll for autoneg to complete if specified to do so */ if (autoneg_wait_to_complete) { @@ -937,14 +1128,12 @@ out: * ixgbe_setup_copper_link_82599 - 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 * * Restarts link on PHY and MAC based on settings passed in. **/ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete) { s32 status; @@ -952,7 +1141,7 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, DEBUGFUNC("ixgbe_setup_copper_link_82599"); /* Setup the PHY according to input speed */ - status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, + status = hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait_to_complete); /* Set up MAC */ ixgbe_start_mac_link_82599(hw, autoneg_wait_to_complete); @@ -972,7 +1161,8 @@ s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) { ixgbe_link_speed link_speed; s32 status; - u32 ctrl, i, autoc, autoc2; + u32 ctrl, i, autoc2; + u32 curr_lms; bool link_up = FALSE; DEBUGFUNC("ixgbe_reset_hw_82599"); @@ -1006,6 +1196,13 @@ s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) if (hw->phy.reset_disable == FALSE && hw->phy.ops.reset != NULL) hw->phy.ops.reset(hw); + /* remember AUTOC from before we reset */ + if (hw->mac.cached_autoc) + curr_lms = hw->mac.cached_autoc & IXGBE_AUTOC_LMS_MASK; + else + curr_lms = IXGBE_READ_REG(hw, IXGBE_AUTOC) & + IXGBE_AUTOC_LMS_MASK; + mac_reset_top: /* * Issue global reset to the MAC. Needs to be SW reset if link is up. @@ -1054,16 +1251,59 @@ mac_reset_top: * stored off yet. Otherwise restore the stored original * values since the reset operation sets back to defaults. */ - autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + + /* Enable link if disabled in NVM */ + if (autoc2 & IXGBE_AUTOC2_LINK_DISABLE_MASK) { + autoc2 &= ~IXGBE_AUTOC2_LINK_DISABLE_MASK; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2); + IXGBE_WRITE_FLUSH(hw); + } + if (hw->mac.orig_link_settings_stored == FALSE) { - hw->mac.orig_autoc = autoc; + hw->mac.orig_autoc = hw->mac.cached_autoc; hw->mac.orig_autoc2 = autoc2; hw->mac.orig_link_settings_stored = TRUE; } else { - if (autoc != hw->mac.orig_autoc) - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (hw->mac.orig_autoc | - IXGBE_AUTOC_AN_RESTART)); + + /* If MNG FW is running on a multi-speed device that + * doesn't autoneg with out driver support we need to + * leave LMS in the state it was before we MAC reset. + * Likewise if we support WoL we don't want change the + * LMS state. + */ + if ((hw->phy.multispeed_fiber && hw->mng_fw_enabled) || + hw->wol_enabled) + hw->mac.orig_autoc = + (hw->mac.orig_autoc & ~IXGBE_AUTOC_LMS_MASK) | + curr_lms; + + if (hw->mac.cached_autoc != hw->mac.orig_autoc) { + /* Need SW/FW semaphore around AUTOC writes if LESM is + * on, likewise reset_pipeline requires us to hold + * this lock as it also writes to AUTOC. + */ + bool got_lock = FALSE; + if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { + status = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (status != IXGBE_SUCCESS) { + status = IXGBE_ERR_SWFW_SYNC; + goto reset_hw_out; + } + + got_lock = TRUE; + } + + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc); + hw->mac.cached_autoc = hw->mac.orig_autoc; + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + } if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) != (hw->mac.orig_autoc2 & IXGBE_AUTOC2_UPPER_MASK)) { @@ -1168,7 +1408,7 @@ s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) & IXGBE_FDIRCTRL_INIT_DONE) break; - usec_delay(10); + msec_delay(1); } if (i >= IXGBE_FDIR_INIT_DONE_POLL) { DEBUGOUT("Flow Director Signature poll time exceeded!\n"); @@ -2098,7 +2338,7 @@ static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) { s32 status = IXGBE_ERR_EEPROM_VERSION; u16 fw_offset, fw_ptp_cfg_offset; - u16 fw_version = 0; + u16 fw_version; DEBUGFUNC("ixgbe_verify_fw_version_82599"); @@ -2109,22 +2349,37 @@ static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw) } /* get the offset to the Firmware Module block */ - hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset); + if (hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset)) { + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", IXGBE_FW_PTR); + return IXGBE_ERR_EEPROM_VERSION; + } if ((fw_offset == 0) || (fw_offset == 0xFFFF)) goto fw_version_out; /* get the offset to the Pass Through Patch Configuration block */ - hw->eeprom.ops.read(hw, (fw_offset + + if (hw->eeprom.ops.read(hw, (fw_offset + IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR), - &fw_ptp_cfg_offset); + &fw_ptp_cfg_offset)) { + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", + fw_offset + + IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR); + return IXGBE_ERR_EEPROM_VERSION; + } if ((fw_ptp_cfg_offset == 0) || (fw_ptp_cfg_offset == 0xFFFF)) goto fw_version_out; /* get the firmware version */ - hw->eeprom.ops.read(hw, (fw_ptp_cfg_offset + - IXGBE_FW_PATCH_VERSION_4), &fw_version); + if (hw->eeprom.ops.read(hw, (fw_ptp_cfg_offset + + IXGBE_FW_PATCH_VERSION_4), &fw_version)) { + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", + fw_ptp_cfg_offset + IXGBE_FW_PATCH_VERSION_4); + return IXGBE_ERR_EEPROM_VERSION; + } if (fw_version > 0x5) status = IXGBE_SUCCESS; @@ -2243,4 +2498,55 @@ static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, return ret_val; } +/** + * ixgbe_reset_pipeline_82599 - perform pipeline reset + * + * @hw: pointer to hardware structure + * + * Reset pipeline by asserting Restart_AN together with LMS change to ensure + * full pipeline reset + **/ +s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw) +{ + s32 ret_val; + u32 anlp1_reg = 0; + u32 i, autoc_reg, autoc2_reg; + + /* Enable link if disabled in NVM */ + autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2); + if (autoc2_reg & IXGBE_AUTOC2_LINK_DISABLE_MASK) { + autoc2_reg &= ~IXGBE_AUTOC2_LINK_DISABLE_MASK; + IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2_reg); + IXGBE_WRITE_FLUSH(hw); + } + + autoc_reg = hw->mac.cached_autoc; + autoc_reg |= IXGBE_AUTOC_AN_RESTART; + /* Write AUTOC register with toggled LMS[2] bit and Restart_AN */ + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg ^ IXGBE_AUTOC_LMS_1G_AN); + /* Wait for AN to leave state 0 */ + for (i = 0; i < 10; i++) { + msec_delay(4); + anlp1_reg = IXGBE_READ_REG(hw, IXGBE_ANLP1); + if (anlp1_reg & IXGBE_ANLP1_AN_STATE_MASK) + break; + } + + if (!(anlp1_reg & IXGBE_ANLP1_AN_STATE_MASK)) { + DEBUGOUT("auto negotiation not completed\n"); + ret_val = IXGBE_ERR_RESET_FAILED; + goto reset_pipeline_out; + } + + ret_val = IXGBE_SUCCESS; + +reset_pipeline_out: + /* Write AUTOC register with original LMS field and Restart_AN */ + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + IXGBE_WRITE_FLUSH(hw); + + return ret_val; +} + + diff --git a/sys/dev/netif/ixgbe/ixgbe_82599.h b/sys/dev/netif/ix/ixgbe_82599.h similarity index 90% rename from sys/dev/netif/ixgbe/ixgbe_82599.h rename to sys/dev/netif/ix/ixgbe_82599.h index 305f4a8634..a77d153aab 100644 --- a/sys/dev/netif/ixgbe/ixgbe_82599.h +++ b/sys/dev/netif/ix/ixgbe_82599.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_82599.h,v 1.1 2012/01/30 16:42:02 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef _IXGBE_82599_H_ #define _IXGBE_82599_H_ @@ -42,15 +42,15 @@ void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, + ixgbe_link_speed speed, bool autoneg_wait_to_complete); s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, + ixgbe_link_speed speed, bool autoneg_wait_to_complete); s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, bool autoneg_wait_to_complete); s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete); + bool autoneg_wait_to_complete); s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw); void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw); s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw); @@ -61,5 +61,4 @@ s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw); s32 ixgbe_init_phy_ops_82599(struct ixgbe_hw *hw); u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval); -bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); #endif /* _IXGBE_82599_H_ */ diff --git a/sys/dev/netif/ixgbe/ixgbe_api.c b/sys/dev/netif/ix/ixgbe_api.c similarity index 94% rename from sys/dev/netif/ixgbe/ixgbe_api.c rename to sys/dev/netif/ix/ixgbe_api.c index 7abbcc5cf6..925866b861 100644 --- a/sys/dev/netif/ixgbe/ixgbe_api.c +++ b/sys/dev/netif/ix/ixgbe_api.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,11 +30,24 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_api.c,v 1.13 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #include "ixgbe_api.h" #include "ixgbe_common.h" +/** + * ixgbe_dcb_get_rtrup2tc - read rtrup2tc reg + * @hw: pointer to hardware structure + * @map: pointer to u8 arr for returning map + * + * Read the rtrup2tc HW register and resolve its content into map + **/ +void ixgbe_dcb_get_rtrup2tc(struct ixgbe_hw *hw, u8 *map) +{ + if (hw->mac.ops.get_rtrup2tc) + hw->mac.ops.get_rtrup2tc(hw, map); +} + /** * ixgbe_init_shared_code - Initialize the shared code * @hw: pointer to hardware structure @@ -93,53 +106,62 @@ s32 ixgbe_set_mac_type(struct ixgbe_hw *hw) DEBUGFUNC("ixgbe_set_mac_type\n"); - if (hw->vendor_id == IXGBE_INTEL_VENDOR_ID) { - switch (hw->device_id) { - case IXGBE_DEV_ID_82598: - case IXGBE_DEV_ID_82598_BX: - case IXGBE_DEV_ID_82598AF_SINGLE_PORT: - case IXGBE_DEV_ID_82598AF_DUAL_PORT: - case IXGBE_DEV_ID_82598AT: - case IXGBE_DEV_ID_82598AT2: - 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: - case IXGBE_DEV_ID_82598EB_SFP_LOM: - hw->mac.type = ixgbe_mac_82598EB; - break; - case IXGBE_DEV_ID_82599_KX4: - case IXGBE_DEV_ID_82599_KX4_MEZZ: - case IXGBE_DEV_ID_82599_XAUI_LOM: - case IXGBE_DEV_ID_82599_COMBO_BACKPLANE: - case IXGBE_DEV_ID_82599_KR: - case IXGBE_DEV_ID_82599_SFP: - case IXGBE_DEV_ID_82599_BACKPLANE_FCOE: - case IXGBE_DEV_ID_82599_SFP_FCOE: - case IXGBE_DEV_ID_82599_SFP_EM: - case IXGBE_DEV_ID_82599_SFP_SF2: - case IXGBE_DEV_ID_82599EN_SFP: - case IXGBE_DEV_ID_82599_CX4: - case IXGBE_DEV_ID_82599_T3_LOM: - hw->mac.type = ixgbe_mac_82599EB; - break; - case IXGBE_DEV_ID_82599_VF: - hw->mac.type = ixgbe_mac_82599_vf; - break; - case IXGBE_DEV_ID_X540_VF: - hw->mac.type = ixgbe_mac_X540_vf; - break; - case IXGBE_DEV_ID_X540T: - case IXGBE_DEV_ID_X540T1: - hw->mac.type = ixgbe_mac_X540; - break; - default: - ret_val = IXGBE_ERR_DEVICE_NOT_SUPPORTED; - break; - } - } else { + if (hw->vendor_id != IXGBE_INTEL_VENDOR_ID) { + ERROR_REPORT2(IXGBE_ERROR_UNSUPPORTED, + "Unsupported vendor id: %x", hw->vendor_id); + return IXGBE_ERR_DEVICE_NOT_SUPPORTED; + } + + switch (hw->device_id) { + case IXGBE_DEV_ID_82598: + case IXGBE_DEV_ID_82598_BX: + case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598AF_DUAL_PORT: + case IXGBE_DEV_ID_82598AT: + case IXGBE_DEV_ID_82598AT2: + 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: + case IXGBE_DEV_ID_82598EB_SFP_LOM: + hw->mac.type = ixgbe_mac_82598EB; + break; + case IXGBE_DEV_ID_82599_KX4: + case IXGBE_DEV_ID_82599_KX4_MEZZ: + case IXGBE_DEV_ID_82599_XAUI_LOM: + case IXGBE_DEV_ID_82599_COMBO_BACKPLANE: + case IXGBE_DEV_ID_82599_KR: + case IXGBE_DEV_ID_82599_SFP: + case IXGBE_DEV_ID_82599_BACKPLANE_FCOE: + case IXGBE_DEV_ID_82599_SFP_FCOE: + case IXGBE_DEV_ID_82599_SFP_EM: + case IXGBE_DEV_ID_82599_SFP_SF2: + case IXGBE_DEV_ID_82599_SFP_SF_QP: + case IXGBE_DEV_ID_82599EN_SFP: + case IXGBE_DEV_ID_82599_CX4: + case IXGBE_DEV_ID_82599_BYPASS: + case IXGBE_DEV_ID_82599_T3_LOM: + hw->mac.type = ixgbe_mac_82599EB; + break; + case IXGBE_DEV_ID_82599_VF: + case IXGBE_DEV_ID_82599_VF_HV: + hw->mac.type = ixgbe_mac_82599_vf; + break; + case IXGBE_DEV_ID_X540_VF: + case IXGBE_DEV_ID_X540_VF_HV: + hw->mac.type = ixgbe_mac_X540_vf; + break; + case IXGBE_DEV_ID_X540T: + case IXGBE_DEV_ID_X540_BYPASS: + hw->mac.type = ixgbe_mac_X540; + break; + default: ret_val = IXGBE_ERR_DEVICE_NOT_SUPPORTED; + ERROR_REPORT2(IXGBE_ERROR_UNSUPPORTED, + "Unsupported device id: %x", + hw->device_id); + break; } DEBUGOUT2("ixgbe_set_mac_type found mac: %d, returns: %d\n", @@ -507,16 +529,14 @@ s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, ixgbe_link_speed *speed, * ixgbe_setup_phy_link_speed - Set auto advertise * @hw: pointer to hardware structure * @speed: new link speed - * @autoneg: TRUE if autonegotiation enabled * * Sets the auto advertised capabilities **/ s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete) { return ixgbe_call_func(hw, hw->phy.ops.setup_link_speed, (hw, speed, - autoneg, autoneg_wait_to_complete), + autoneg_wait_to_complete), IXGBE_NOT_IMPLEMENTED); } @@ -576,17 +596,15 @@ void ixgbe_flap_tx_laser(struct ixgbe_hw *hw) * ixgbe_setup_link - Set link speed * @hw: pointer to hardware structure * @speed: new link speed - * @autoneg: TRUE if autonegotiation enabled * * Configures link settings. Restarts the link. * Performs autonegotiation if needed. **/ s32 ixgbe_setup_link(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete) { return ixgbe_call_func(hw, hw->mac.ops.setup_link, (hw, speed, - autoneg, autoneg_wait_to_complete), + autoneg_wait_to_complete), IXGBE_NOT_IMPLEMENTED); } @@ -999,6 +1017,8 @@ s32 ixgbe_set_fw_drv_ver(struct ixgbe_hw *hw, u8 maj, u8 min, u8 build, } + + /** * ixgbe_read_analog_reg8 - Reads 8 bit analog register * @hw: pointer to hardware structure diff --git a/sys/dev/netif/ixgbe/ixgbe_api.h b/sys/dev/netif/ix/ixgbe_api.h similarity index 96% rename from sys/dev/netif/ixgbe/ixgbe_api.h rename to sys/dev/netif/ix/ixgbe_api.h index b5f5a1bce0..91023ae58c 100644 --- a/sys/dev/netif/ixgbe/ixgbe_api.h +++ b/sys/dev/netif/ix/ixgbe_api.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,13 +30,15 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_api.h,v 1.14 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef _IXGBE_API_H_ #define _IXGBE_API_H_ #include "ixgbe_type.h" +void ixgbe_dcb_get_rtrup2tc(struct ixgbe_hw *hw, u8 *map); + s32 ixgbe_init_shared_code(struct ixgbe_hw *hw); extern s32 ixgbe_init_ops_82598(struct ixgbe_hw *hw); @@ -72,13 +74,12 @@ s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, bool *link_up); s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete); void ixgbe_disable_tx_laser(struct ixgbe_hw *hw); void ixgbe_enable_tx_laser(struct ixgbe_hw *hw); void ixgbe_flap_tx_laser(struct ixgbe_hw *hw); s32 ixgbe_setup_link(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete); + bool autoneg_wait_to_complete); s32 ixgbe_check_link(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up, bool link_up_wait_to_complete); s32 ixgbe_get_link_capabilities(struct ixgbe_hw *hw, ixgbe_link_speed *speed, @@ -135,6 +136,7 @@ u32 ixgbe_get_supported_physical_layer(struct ixgbe_hw *hw); s32 ixgbe_enable_rx_dma(struct ixgbe_hw *hw, u32 regval); s32 ixgbe_disable_sec_rx_path(struct ixgbe_hw *hw); s32 ixgbe_enable_sec_rx_path(struct ixgbe_hw *hw); +s32 ixgbe_mng_fw_enabled(struct ixgbe_hw *hw); s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw); s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 fdirctrl); s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 fdirctrl); @@ -159,6 +161,7 @@ void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input, union ixgbe_atr_input *mask); u32 ixgbe_atr_compute_sig_hash_82599(union ixgbe_atr_hash_dword input, union ixgbe_atr_hash_dword common); +bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); s32 ixgbe_read_i2c_byte(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data); s32 ixgbe_write_i2c_byte(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, diff --git a/sys/dev/netif/ixgbe/ixgbe_common.c b/sys/dev/netif/ix/ixgbe_common.c similarity index 88% rename from sys/dev/netif/ixgbe/ixgbe_common.c rename to sys/dev/netif/ix/ixgbe_common.c index f110208029..17343450dd 100644 --- a/sys/dev/netif/ixgbe/ixgbe_common.c +++ b/sys/dev/netif/ix/ixgbe_common.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,10 +30,12 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_common.c,v 1.14 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #include "ixgbe_common.h" #include "ixgbe_phy.h" +#include "ixgbe_dcb.h" +#include "ixgbe_dcb_82599.h" #include "ixgbe_api.h" static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw); @@ -134,33 +136,63 @@ s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw) mac->ops.get_link_capabilities = NULL; mac->ops.setup_link = NULL; mac->ops.check_link = NULL; + mac->ops.dmac_config = NULL; + mac->ops.dmac_update_tcs = NULL; + mac->ops.dmac_config_tcs = NULL; return IXGBE_SUCCESS; } /** - * ixgbe_device_supports_autoneg_fc - Check if phy supports autoneg flow - * control - * @hw: pointer to hardware structure + * ixgbe_device_supports_autoneg_fc - Check if device supports autonegotiation + * of flow control + * @hw: pointer to hardware structure + * + * This function returns TRUE if the device supports flow control + * autonegotiation, and FALSE if it does not. * - * There are several phys that do not support autoneg flow control. This - * function check the device id to see if the associated phy supports - * autoneg flow control. **/ -static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) +bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw) { + bool supported = FALSE; + ixgbe_link_speed speed; + bool link_up; DEBUGFUNC("ixgbe_device_supports_autoneg_fc"); - switch (hw->device_id) { - case IXGBE_DEV_ID_X540T: - case IXGBE_DEV_ID_X540T1: - return IXGBE_SUCCESS; - case IXGBE_DEV_ID_82599_T3_LOM: - return IXGBE_SUCCESS; + switch (hw->phy.media_type) { + case ixgbe_media_type_fiber_fixed: + case ixgbe_media_type_fiber: + hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); + /* if link is down, assume supported */ + if (link_up) + supported = speed == IXGBE_LINK_SPEED_1GB_FULL ? + TRUE : FALSE; + else + supported = TRUE; + break; + case ixgbe_media_type_backplane: + supported = TRUE; + break; + case ixgbe_media_type_copper: + /* only some copper devices support flow control autoneg */ + switch (hw->device_id) { + case IXGBE_DEV_ID_82599_T3_LOM: + case IXGBE_DEV_ID_X540T: + case IXGBE_DEV_ID_X540_BYPASS: + supported = TRUE; + break; + default: + supported = FALSE; + } default: - return IXGBE_ERR_FC_NOT_SUPPORTED; + break; } + + ERROR_REPORT2(IXGBE_ERROR_UNSUPPORTED, + "Device %x does not support flow control autoneg", + hw->device_id); + return supported; } /** @@ -174,6 +206,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) s32 ret_val = IXGBE_SUCCESS; u32 reg = 0, reg_bp = 0; u16 reg_cu = 0; + bool got_lock = FALSE; DEBUGFUNC("ixgbe_setup_fc"); @@ -182,7 +215,8 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) * ixgbe_fc_rx_pause because it will cause us to fail at UNH. */ if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) { - DEBUGOUT("ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); + ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, + "ixgbe_fc_rx_pause not valid in strict IEEE mode\n"); ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; goto out; } @@ -200,6 +234,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) * we link at 10G, the 1G advertisement is harmless and vice versa. */ switch (hw->phy.media_type) { + case ixgbe_media_type_fiber_fixed: case ixgbe_media_type_fiber: case ixgbe_media_type_backplane: reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); @@ -268,7 +303,8 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) reg_cu |= IXGBE_TAF_SYM_PAUSE | IXGBE_TAF_ASM_PAUSE; break; default: - DEBUGOUT("Flow control param set incorrectly\n"); + ERROR_REPORT1(IXGBE_ERROR_ARGUMENT, + "Flow control param set incorrectly\n"); ret_val = IXGBE_ERR_CONFIG; goto out; break; @@ -297,9 +333,30 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) */ if (hw->phy.media_type == ixgbe_media_type_backplane) { reg_bp |= IXGBE_AUTOC_AN_RESTART; + /* Need the SW/FW semaphore around AUTOC writes if 82599 and + * LESM is on, likewise reset_pipeline requries the lock as + * it also writes AUTOC. + */ + if ((hw->mac.type == ixgbe_mac_82599EB) && + ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (ret_val != IXGBE_SUCCESS) { + ret_val = IXGBE_ERR_SWFW_SYNC; + goto out; + } + got_lock = TRUE; + } + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_bp); + if (hw->mac.type == ixgbe_mac_82599EB) + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); } else if ((hw->phy.media_type == ixgbe_media_type_copper) && - (ixgbe_device_supports_autoneg_fc(hw) == IXGBE_SUCCESS)) { + (ixgbe_device_supports_autoneg_fc(hw))) { hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_ADVT, IXGBE_MDIO_AUTO_NEG_DEV_TYPE, reg_cu); } @@ -679,6 +736,195 @@ s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num) return IXGBE_SUCCESS; } +/** + * ixgbe_read_pba_raw + * @hw: pointer to the HW structure + * @eeprom_buf: optional pointer to EEPROM image + * @eeprom_buf_size: size of EEPROM image in words + * @max_pba_block_size: PBA block size limit + * @pba: pointer to output PBA structure + * + * Reads PBA from EEPROM image when eeprom_buf is not NULL. + * Reads PBA from physical EEPROM device when eeprom_buf is NULL. + * + **/ +s32 ixgbe_read_pba_raw(struct ixgbe_hw *hw, u16 *eeprom_buf, + u32 eeprom_buf_size, u16 max_pba_block_size, + struct ixgbe_pba *pba) +{ + s32 ret_val; + u16 pba_block_size; + + if (pba == NULL) + return IXGBE_ERR_PARAM; + + if (eeprom_buf == NULL) { + ret_val = hw->eeprom.ops.read_buffer(hw, IXGBE_PBANUM0_PTR, 2, + &pba->word[0]); + if (ret_val) + return ret_val; + } else { + if (eeprom_buf_size > IXGBE_PBANUM1_PTR) { + pba->word[0] = eeprom_buf[IXGBE_PBANUM0_PTR]; + pba->word[1] = eeprom_buf[IXGBE_PBANUM1_PTR]; + } else { + return IXGBE_ERR_PARAM; + } + } + + if (pba->word[0] == IXGBE_PBANUM_PTR_GUARD) { + if (pba->pba_block == NULL) + return IXGBE_ERR_PARAM; + + ret_val = ixgbe_get_pba_block_size(hw, eeprom_buf, + eeprom_buf_size, + &pba_block_size); + if (ret_val) + return ret_val; + + if (pba_block_size > max_pba_block_size) + return IXGBE_ERR_PARAM; + + if (eeprom_buf == NULL) { + ret_val = hw->eeprom.ops.read_buffer(hw, pba->word[1], + pba_block_size, + pba->pba_block); + if (ret_val) + return ret_val; + } else { + if (eeprom_buf_size > (u32)(pba->word[1] + + pba->pba_block[0])) { + memcpy(pba->pba_block, + &eeprom_buf[pba->word[1]], + pba_block_size * sizeof(u16)); + } else { + return IXGBE_ERR_PARAM; + } + } + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_write_pba_raw + * @hw: pointer to the HW structure + * @eeprom_buf: optional pointer to EEPROM image + * @eeprom_buf_size: size of EEPROM image in words + * @pba: pointer to PBA structure + * + * Writes PBA to EEPROM image when eeprom_buf is not NULL. + * Writes PBA to physical EEPROM device when eeprom_buf is NULL. + * + **/ +s32 ixgbe_write_pba_raw(struct ixgbe_hw *hw, u16 *eeprom_buf, + u32 eeprom_buf_size, struct ixgbe_pba *pba) +{ + s32 ret_val; + + if (pba == NULL) + return IXGBE_ERR_PARAM; + + if (eeprom_buf == NULL) { + ret_val = hw->eeprom.ops.write_buffer(hw, IXGBE_PBANUM0_PTR, 2, + &pba->word[0]); + if (ret_val) + return ret_val; + } else { + if (eeprom_buf_size > IXGBE_PBANUM1_PTR) { + eeprom_buf[IXGBE_PBANUM0_PTR] = pba->word[0]; + eeprom_buf[IXGBE_PBANUM1_PTR] = pba->word[1]; + } else { + return IXGBE_ERR_PARAM; + } + } + + if (pba->word[0] == IXGBE_PBANUM_PTR_GUARD) { + if (pba->pba_block == NULL) + return IXGBE_ERR_PARAM; + + if (eeprom_buf == NULL) { + ret_val = hw->eeprom.ops.write_buffer(hw, pba->word[1], + pba->pba_block[0], + pba->pba_block); + if (ret_val) + return ret_val; + } else { + if (eeprom_buf_size > (u32)(pba->word[1] + + pba->pba_block[0])) { + memcpy(&eeprom_buf[pba->word[1]], + pba->pba_block, + pba->pba_block[0] * sizeof(u16)); + } else { + return IXGBE_ERR_PARAM; + } + } + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_get_pba_block_size + * @hw: pointer to the HW structure + * @eeprom_buf: optional pointer to EEPROM image + * @eeprom_buf_size: size of EEPROM image in words + * @pba_data_size: pointer to output variable + * + * Returns the size of the PBA block in words. Function operates on EEPROM + * image if the eeprom_buf pointer is not NULL otherwise it accesses physical + * EEPROM device. + * + **/ +s32 ixgbe_get_pba_block_size(struct ixgbe_hw *hw, u16 *eeprom_buf, + u32 eeprom_buf_size, u16 *pba_block_size) +{ + s32 ret_val; + u16 pba_word[2]; + u16 length; + + DEBUGFUNC("ixgbe_get_pba_block_size"); + + if (eeprom_buf == NULL) { + ret_val = hw->eeprom.ops.read_buffer(hw, IXGBE_PBANUM0_PTR, 2, + &pba_word[0]); + if (ret_val) + return ret_val; + } else { + if (eeprom_buf_size > IXGBE_PBANUM1_PTR) { + pba_word[0] = eeprom_buf[IXGBE_PBANUM0_PTR]; + pba_word[1] = eeprom_buf[IXGBE_PBANUM1_PTR]; + } else { + return IXGBE_ERR_PARAM; + } + } + + if (pba_word[0] == IXGBE_PBANUM_PTR_GUARD) { + if (eeprom_buf == NULL) { + ret_val = hw->eeprom.ops.read(hw, pba_word[1] + 0, + &length); + if (ret_val) + return ret_val; + } else { + if (eeprom_buf_size > pba_word[1]) + length = eeprom_buf[pba_word[1] + 0]; + else + return IXGBE_ERR_PARAM; + } + + if (length == 0xFFFF || length == 0) + return IXGBE_ERR_PBA_SECTION; + } else { + /* PBA number in legacy format, there is no PBA Block. */ + length = 0; + } + + if (pba_block_size != NULL) + *pba_block_size = length; + + return IXGBE_SUCCESS; +} + /** * ixgbe_get_mac_addr_generic - Generic get MAC address * @hw: pointer to hardware structure @@ -709,23 +955,18 @@ s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr) } /** - * ixgbe_get_bus_info_generic - Generic set PCI bus info + * ixgbe_set_pci_config_data_generic - Generic store PCI bus info * @hw: pointer to hardware structure + * @link_status: the link status returned by the PCI config space * - * Sets the PCI bus info (speed, width, type) within the ixgbe_hw structure + * Stores the PCI bus info (speed, width, type) within the ixgbe_hw structure **/ -s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw) +void ixgbe_set_pci_config_data_generic(struct ixgbe_hw *hw, u16 link_status) { struct ixgbe_mac_info *mac = &hw->mac; - u16 link_status; - - DEBUGFUNC("ixgbe_get_bus_info_generic"); 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; @@ -760,6 +1001,25 @@ s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw) } mac->ops.set_lan_id(hw); +} + +/** + * ixgbe_get_bus_info_generic - Generic set PCI bus info + * @hw: pointer to hardware structure + * + * Gets the PCI bus info (speed, width, type) then calls helper function to + * store this data within the ixgbe_hw structure. + **/ +s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw) +{ + u16 link_status; + + DEBUGFUNC("ixgbe_get_bus_info_generic"); + + /* Get the negotiated link width and speed from PCI config space */ + link_status = IXGBE_READ_PCIE_WORD(hw, IXGBE_PCI_LINK_STATUS); + + ixgbe_set_pci_config_data_generic(hw, link_status); return IXGBE_SUCCESS; } @@ -1259,16 +1519,18 @@ s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset, if (words == 0) { status = IXGBE_ERR_INVALID_ARGUMENT; + ERROR_REPORT1(IXGBE_ERROR_ARGUMENT, "Invalid EEPROM words"); goto out; } if (offset >= hw->eeprom.word_size) { status = IXGBE_ERR_EEPROM; + ERROR_REPORT1(IXGBE_ERROR_ARGUMENT, "Invalid EEPROM offset"); goto out; } for (i = 0; i < words; i++) { - eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) + + eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) | IXGBE_EEPROM_RW_REG_START; IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd); @@ -1365,11 +1627,13 @@ s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset, if (words == 0) { status = IXGBE_ERR_INVALID_ARGUMENT; + ERROR_REPORT1(IXGBE_ERROR_ARGUMENT, "Invalid EEPROM words"); goto out; } if (offset >= hw->eeprom.word_size) { status = IXGBE_ERR_EEPROM; + ERROR_REPORT1(IXGBE_ERROR_ARGUMENT, "Invalid EEPROM offset"); goto out; } @@ -1438,6 +1702,11 @@ s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg) } usec_delay(5); } + + if (i == IXGBE_EERD_EEWR_ATTEMPTS) + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "EEPROM read/write done polling timed out"); + return status; } @@ -1573,14 +1842,15 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw) * was not granted because we don't have access to the EEPROM */ if (i >= timeout) { - DEBUGOUT("SWESMBI Software EEPROM semaphore " - "not granted.\n"); + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "SWESMBI Software EEPROM semaphore not granted.\n"); ixgbe_release_eeprom_semaphore(hw); status = IXGBE_ERR_EEPROM; } } else { - DEBUGOUT("Software semaphore SMBI between device drivers " - "not granted.\n"); + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "Software semaphore SMBI between device drivers " + "not granted.\n"); } return status; @@ -1633,7 +1903,7 @@ static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw) usec_delay(5); ixgbe_standby_eeprom(hw); - } + }; /* * On some parts, SPI write time could vary from 0-20mSec on 3.3V @@ -1719,7 +1989,7 @@ static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, * EEPROM */ mask = mask >> 1; - } + }; /* We leave the "DI" bit set to "0" when we leave this routine. */ eec &= ~IXGBE_EEC_DI; @@ -2004,7 +2274,8 @@ s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, /* Make sure we are using a valid rar index range */ if (index >= rar_entries) { - DEBUGOUT1("RAR index %d is out of range.\n", index); + ERROR_REPORT2(IXGBE_ERROR_ARGUMENT, + "RAR index %d is out of range.\n", index); return IXGBE_ERR_INVALID_ARGUMENT; } @@ -2053,7 +2324,8 @@ s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index) /* Make sure we are using a valid rar index range */ if (index >= rar_entries) { - DEBUGOUT1("RAR index %d is out of range.\n", index); + ERROR_REPORT2(IXGBE_ERROR_ARGUMENT, + "RAR index %d is out of range.\n", index); return IXGBE_ERR_INVALID_ARGUMENT; } @@ -2496,7 +2768,8 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) fccfg_reg |= IXGBE_FCCFG_TFCE_802_3X; break; default: - DEBUGOUT("Flow control param set incorrectly\n"); + ERROR_REPORT1(IXGBE_ERROR_ARGUMENT, + "Flow control param set incorrectly\n"); ret_val = IXGBE_ERR_CONFIG; goto out; break; @@ -2557,8 +2830,13 @@ out: static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg, u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm) { - if ((!(adv_reg)) || (!(lp_reg))) + if ((!(adv_reg)) || (!(lp_reg))) { + ERROR_REPORT3(IXGBE_ERROR_UNSUPPORTED, + "Local or link partner's advertised flow control " + "settings are NULL. Local: %x, link partner: %x\n", + adv_reg, lp_reg); return IXGBE_ERR_FC_NOT_NEGOTIATED; + } if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) { /* @@ -2609,8 +2887,11 @@ static s32 ixgbe_fc_autoneg_fiber(struct ixgbe_hw *hw) linkstat = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA); if ((!!(linkstat & IXGBE_PCS1GLSTA_AN_COMPLETE) == 0) || - (!!(linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) + (!!(linkstat & IXGBE_PCS1GLSTA_AN_TIMED_OUT) == 1)) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "Auto-Negotiation did not complete or timed out"); goto out; + } pcs_anadv_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); pcs_lpab_reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP); @@ -2642,13 +2923,19 @@ static s32 ixgbe_fc_autoneg_backplane(struct ixgbe_hw *hw) * - we are 82599 and link partner is not AN enabled */ links = IXGBE_READ_REG(hw, IXGBE_LINKS); - if ((links & IXGBE_LINKS_KX_AN_COMP) == 0) + if ((links & IXGBE_LINKS_KX_AN_COMP) == 0) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "Auto-Negotiation did not complete"); goto out; + } if (hw->mac.type == ixgbe_mac_82599EB) { links2 = IXGBE_READ_REG(hw, IXGBE_LINKS2); - if ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0) + if ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0) { + ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, + "Link partner is not AN enabled"); goto out; + } } /* * Read the 10g AN autoc and LP ability registers and resolve @@ -2710,15 +2997,21 @@ void ixgbe_fc_autoneg(struct ixgbe_hw *hw) * - FC autoneg is disabled, or if * - link is not up. */ - if (hw->fc.disable_fc_autoneg) + if (hw->fc.disable_fc_autoneg) { + ERROR_REPORT1(IXGBE_ERROR_UNSUPPORTED, + "Flow control autoneg is disabled"); goto out; + } hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); - if (!link_up) + if (!link_up) { + ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, "The link is down"); goto out; + } switch (hw->phy.media_type) { /* Autoneg flow control on fiber adapters */ + case ixgbe_media_type_fiber_fixed: case ixgbe_media_type_fiber: if (speed == IXGBE_LINK_SPEED_1GB_FULL) ret_val = ixgbe_fc_autoneg_fiber(hw); @@ -2731,7 +3024,7 @@ void ixgbe_fc_autoneg(struct ixgbe_hw *hw) /* Autoneg flow control on copper adapters */ case ixgbe_media_type_copper: - if (ixgbe_device_supports_autoneg_fc(hw) == IXGBE_SUCCESS) + if (ixgbe_device_supports_autoneg_fc(hw)) ret_val = ixgbe_fc_autoneg_copper(hw); break; @@ -2748,6 +3041,53 @@ out: } } +/* + * ixgbe_pcie_timeout_poll - Return number of times to poll for completion + * @hw: pointer to hardware structure + * + * System-wide timeout range is encoded in PCIe Device Control2 register. + * + * Add 10% to specified maximum and return the number of times to poll for + * completion timeout, in units of 100 microsec. Never return less than + * 800 = 80 millisec. + */ +static u32 ixgbe_pcie_timeout_poll(struct ixgbe_hw *hw) +{ + s16 devctl2; + u32 pollcnt; + + devctl2 = IXGBE_READ_PCIE_WORD(hw, IXGBE_PCI_DEVICE_CONTROL2); + devctl2 &= IXGBE_PCIDEVCTRL2_TIMEO_MASK; + + switch (devctl2) { + case IXGBE_PCIDEVCTRL2_65_130ms: + pollcnt = 1300; /* 130 millisec */ + break; + case IXGBE_PCIDEVCTRL2_260_520ms: + pollcnt = 5200; /* 520 millisec */ + break; + case IXGBE_PCIDEVCTRL2_1_2s: + pollcnt = 20000; /* 2 sec */ + break; + case IXGBE_PCIDEVCTRL2_4_8s: + pollcnt = 80000; /* 8 sec */ + break; + case IXGBE_PCIDEVCTRL2_17_34s: + pollcnt = 34000; /* 34 sec */ + break; + case IXGBE_PCIDEVCTRL2_50_100us: /* 100 microsecs */ + case IXGBE_PCIDEVCTRL2_1_2ms: /* 2 millisecs */ + case IXGBE_PCIDEVCTRL2_16_32ms: /* 32 millisec */ + case IXGBE_PCIDEVCTRL2_16_32ms_def: /* 32 millisec default */ + default: + pollcnt = 800; /* 80 millisec minimum */ + break; + } + + /* add 10% to spec maximum */ + return (pollcnt * 11) / 10; +} + /** * ixgbe_disable_pcie_master - Disable PCI-express master access * @hw: pointer to hardware structure @@ -2760,14 +3100,14 @@ out: s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) { s32 status = IXGBE_SUCCESS; - u32 i; + u32 i, poll; DEBUGFUNC("ixgbe_disable_pcie_master"); /* Always set this bit to ensure any future transactions are blocked */ IXGBE_WRITE_REG(hw, IXGBE_CTRL, IXGBE_CTRL_GIO_DIS); - /* Exit if master requets are blocked */ + /* Exit if master requests are blocked */ if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) goto out; @@ -2793,14 +3133,16 @@ s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) * Before proceeding, make sure that the PCIe block does not have * transactions pending. */ - for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { + poll = ixgbe_pcie_timeout_poll(hw); + for (i = 0; i < poll; i++) { usec_delay(100); if (!(IXGBE_READ_PCIE_WORD(hw, IXGBE_PCI_DEVICE_STATUS) & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING)) goto out; } - DEBUGOUT("PCIe transaction pending bit also did not clear.\n"); + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "PCIe transaction pending bit also did not clear.\n"); status = IXGBE_ERR_MASTER_REQUESTS_PENDING; out: @@ -2817,44 +3159,41 @@ out: **/ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask) { - u32 gssr; + u32 gssr = 0; u32 swmask = mask; u32 fwmask = mask << 5; - s32 timeout = 200; + u32 timeout = 200; + u32 i; DEBUGFUNC("ixgbe_acquire_swfw_sync"); - while (timeout) { + for (i = 0; i < timeout; i++) { /* - * SW EEPROM semaphore bit is used for access to all - * SW_FW_SYNC/GSSR bits (not just EEPROM) + * SW NVM semaphore bit is used for access to all + * SW_FW_SYNC bits (not just NVM) */ 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, SW_FW_SYNC timeout.\n"); - return IXGBE_ERR_SWFW_SYNC; + if (!(gssr & (fwmask | swmask))) { + gssr |= swmask; + IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); + ixgbe_release_eeprom_semaphore(hw); + return IXGBE_SUCCESS; + } else { + /* Resource is currently in use by FW or SW */ + ixgbe_release_eeprom_semaphore(hw); + msec_delay(5); + } } - gssr |= swmask; - IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr); + /* If time expired clear the bits holding the lock and retry */ + if (gssr & (fwmask | swmask)) + ixgbe_release_swfw_sync(hw, gssr & (fwmask | swmask)); - ixgbe_release_eeprom_semaphore(hw); - return IXGBE_SUCCESS; + msec_delay(5); + return IXGBE_ERR_SWFW_SYNC; } /** @@ -2965,6 +3304,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) bool link_up = 0; u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + s32 ret_val = IXGBE_SUCCESS; DEBUGFUNC("ixgbe_blink_led_start_generic"); @@ -2975,10 +3315,29 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) hw->mac.ops.check_link(hw, &speed, &link_up, FALSE); if (!link_up) { + /* Need the SW/FW semaphore around AUTOC writes if 82599 and + * LESM is on. + */ + bool got_lock = FALSE; + if ((hw->mac.type == ixgbe_mac_82599EB) && + ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (ret_val != IXGBE_SUCCESS) { + ret_val = IXGBE_ERR_SWFW_SYNC; + goto out; + } + got_lock = TRUE; + } + autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); IXGBE_WRITE_FLUSH(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); msec_delay(10); } @@ -2987,7 +3346,8 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); IXGBE_WRITE_FLUSH(hw); - return IXGBE_SUCCESS; +out: + return ret_val; } /** @@ -2999,21 +3359,43 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) { u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + s32 ret_val = IXGBE_SUCCESS; + bool got_lock = FALSE; DEBUGFUNC("ixgbe_blink_led_stop_generic"); + /* Need the SW/FW semaphore around AUTOC writes if 82599 and + * LESM is on. + */ + if ((hw->mac.type == ixgbe_mac_82599EB) && + ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (ret_val != IXGBE_SUCCESS) { + ret_val = IXGBE_ERR_SWFW_SYNC; + goto out; + } + got_lock = TRUE; + } autoc_reg &= ~IXGBE_AUTOC_FLU; autoc_reg |= IXGBE_AUTOC_AN_RESTART; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + if (hw->mac.type == ixgbe_mac_82599EB) + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + led_reg &= ~IXGBE_LED_MODE_MASK(index); led_reg &= ~IXGBE_LED_BLINK(index); led_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index); IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); IXGBE_WRITE_FLUSH(hw); - return IXGBE_SUCCESS; +out: + return ret_val; } /** @@ -3028,15 +3410,23 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) static s32 ixgbe_get_san_mac_addr_offset(struct ixgbe_hw *hw, u16 *san_mac_offset) { + s32 ret_val; + DEBUGFUNC("ixgbe_get_san_mac_addr_offset"); /* * First read the EEPROM pointer to see if the MAC addresses are * available. */ - hw->eeprom.ops.read(hw, IXGBE_SAN_MAC_ADDR_PTR, san_mac_offset); + ret_val = hw->eeprom.ops.read(hw, IXGBE_SAN_MAC_ADDR_PTR, + san_mac_offset); + if (ret_val) { + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom at offset %d failed", + IXGBE_SAN_MAC_ADDR_PTR); + } - return IXGBE_SUCCESS; + return ret_val; } /** @@ -3053,6 +3443,7 @@ s32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) { u16 san_mac_data, san_mac_offset; u8 i; + s32 ret_val; DEBUGFUNC("ixgbe_get_san_mac_addr_generic"); @@ -3060,18 +3451,9 @@ s32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) * First read the EEPROM pointer to see if the MAC addresses are * available. If they're not, no point in calling set_lan_id() here. */ - ixgbe_get_san_mac_addr_offset(hw, &san_mac_offset); - - if ((san_mac_offset == 0) || (san_mac_offset == 0xFFFF)) { - /* - * No addresses available in this EEPROM. It's not an - * error though, so just wipe the local address and return. - */ - for (i = 0; i < 6; i++) - san_mac_addr[i] = 0xFF; - + ret_val = ixgbe_get_san_mac_addr_offset(hw, &san_mac_offset); + if (ret_val || san_mac_offset == 0 || san_mac_offset == 0xFFFF) goto san_mac_addr_out; - } /* make sure we know which port we need to program */ hw->mac.ops.set_lan_id(hw); @@ -3079,13 +3461,27 @@ s32 ixgbe_get_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) (hw->bus.func) ? (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT1_OFFSET) : (san_mac_offset += IXGBE_SAN_MAC_ADDR_PORT0_OFFSET); for (i = 0; i < 3; i++) { - hw->eeprom.ops.read(hw, san_mac_offset, &san_mac_data); + ret_val = hw->eeprom.ops.read(hw, san_mac_offset, + &san_mac_data); + if (ret_val) { + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", + san_mac_offset); + goto san_mac_addr_out; + } san_mac_addr[i * 2] = (u8)(san_mac_data); san_mac_addr[i * 2 + 1] = (u8)(san_mac_data >> 8); san_mac_offset++; } + return IXGBE_SUCCESS; san_mac_addr_out: + /* + * No addresses available in this EEPROM. It's not an + * error though, so just wipe the local address and return. + */ + for (i = 0; i < 6; i++) + san_mac_addr[i] = 0xFF; return IXGBE_SUCCESS; } @@ -3098,19 +3494,16 @@ san_mac_addr_out: **/ s32 ixgbe_set_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) { - s32 status = IXGBE_SUCCESS; + s32 ret_val; u16 san_mac_data, san_mac_offset; u8 i; DEBUGFUNC("ixgbe_set_san_mac_addr_generic"); /* Look for SAN mac address pointer. If not defined, return */ - ixgbe_get_san_mac_addr_offset(hw, &san_mac_offset); - - if ((san_mac_offset == 0) || (san_mac_offset == 0xFFFF)) { - status = IXGBE_ERR_NO_SAN_ADDR_PTR; - goto san_mac_addr_out; - } + ret_val = ixgbe_get_san_mac_addr_offset(hw, &san_mac_offset); + if (ret_val || san_mac_offset == 0 || san_mac_offset == 0xFFFF) + return IXGBE_ERR_NO_SAN_ADDR_PTR; /* Make sure we know which port we need to write */ hw->mac.ops.set_lan_id(hw); @@ -3125,8 +3518,7 @@ s32 ixgbe_set_san_mac_addr_generic(struct ixgbe_hw *hw, u8 *san_mac_addr) san_mac_offset++; } -san_mac_addr_out: - return status; + return IXGBE_SUCCESS; } /** @@ -3253,7 +3645,8 @@ s32 ixgbe_clear_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) /* Make sure we are using a valid rar index range */ if (rar >= rar_entries) { - DEBUGOUT1("RAR index %d is out of range.\n", rar); + ERROR_REPORT2(IXGBE_ERROR_ARGUMENT, + "RAR index %d is out of range.\n", rar); return IXGBE_ERR_INVALID_ARGUMENT; } @@ -3302,7 +3695,8 @@ s32 ixgbe_set_vmdq_generic(struct ixgbe_hw *hw, u32 rar, u32 vmdq) /* Make sure we are using a valid rar index range */ if (rar >= rar_entries) { - DEBUGOUT1("RAR index %d is out of range.\n", rar); + ERROR_REPORT2(IXGBE_ERROR_ARGUMENT, + "RAR index %d is out of range.\n", rar); return IXGBE_ERR_INVALID_ARGUMENT; } @@ -3401,7 +3795,8 @@ s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan) if (first_empty_slot) regindex = first_empty_slot; else { - DEBUGOUT("No space in VLVF.\n"); + ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, + "No space in VLVF.\n"); regindex = IXGBE_ERR_NO_SPACE; } } @@ -3691,8 +4086,9 @@ s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, *wwpn_prefix = 0xFFFF; /* check if alternative SAN MAC is supported */ - hw->eeprom.ops.read(hw, IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR, - &alt_san_mac_blk_offset); + offset = IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR; + if (hw->eeprom.ops.read(hw, offset, &alt_san_mac_blk_offset)) + goto wwn_prefix_err; if ((alt_san_mac_blk_offset == 0) || (alt_san_mac_blk_offset == 0xFFFF)) @@ -3700,19 +4096,29 @@ s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, /* check capability in alternative san mac address block */ offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET; - hw->eeprom.ops.read(hw, offset, &caps); + if (hw->eeprom.ops.read(hw, offset, &caps)) + goto wwn_prefix_err; if (!(caps & IXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN)) goto wwn_prefix_out; /* get the corresponding prefix for WWNN/WWPN */ offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWNN_OFFSET; - hw->eeprom.ops.read(hw, offset, wwnn_prefix); + if (hw->eeprom.ops.read(hw, offset, wwnn_prefix)) { + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", offset); + } offset = alt_san_mac_blk_offset + IXGBE_ALT_SAN_MAC_ADDR_WWPN_OFFSET; - hw->eeprom.ops.read(hw, offset, wwpn_prefix); + if (hw->eeprom.ops.read(hw, offset, wwpn_prefix)) + goto wwn_prefix_err; wwn_prefix_out: return IXGBE_SUCCESS; + +wwn_prefix_err: + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", offset); + return IXGBE_SUCCESS; } /** @@ -3882,7 +4288,7 @@ void ixgbe_enable_relaxed_ordering_gen2(struct ixgbe_hw *hw) * Calculates the checksum for some buffer on a specified length. The * checksum calculated is returned. **/ -static u8 ixgbe_calculate_checksum(u8 *buffer, u32 length) +u8 ixgbe_calculate_checksum(u8 *buffer, u32 length) { u32 i; u8 sum = 0; @@ -3908,8 +4314,8 @@ static u8 ixgbe_calculate_checksum(u8 *buffer, u32 length) * Communicates with the manageability block. On success return IXGBE_SUCCESS * else return IXGBE_ERR_HOST_INTERFACE_COMMAND. **/ -static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, - u32 length) +s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, + u32 length) { u32 hicr, i, bi; u32 hdr_size = sizeof(struct ixgbe_hic_hdr); @@ -4158,3 +4564,21 @@ void ixgbe_clear_tx_pending(struct ixgbe_hw *hw) IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); } + +/** + * ixgbe_dcb_get_rtrup2tc_generic - read rtrup2tc reg + * @hw: pointer to hardware structure + * @map: pointer to u8 arr for returning map + * + * Read the rtrup2tc HW register and resolve its content into map + **/ +void ixgbe_dcb_get_rtrup2tc_generic(struct ixgbe_hw *hw, u8 *map) +{ + u32 reg, i; + + reg = IXGBE_READ_REG(hw, IXGBE_RTRUP2TC); + for (i = 0; i < IXGBE_DCB_MAX_USER_PRIORITY; i++) + map[i] = IXGBE_RTRUP2TC_UP_MASK & + (reg >> (i * IXGBE_RTRUP2TC_UP_SHIFT)); + return; +} diff --git a/sys/dev/netif/ixgbe/ixgbe_common.h b/sys/dev/netif/ix/ixgbe_common.h similarity index 86% rename from sys/dev/netif/ixgbe/ixgbe_common.h rename to sys/dev/netif/ix/ixgbe_common.h index 0dad30e2a6..7d1ee824c5 100644 --- a/sys/dev/netif/ixgbe/ixgbe_common.h +++ b/sys/dev/netif/ix/ixgbe_common.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_common.h,v 1.12 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef _IXGBE_COMMON_H_ #define _IXGBE_COMMON_H_ @@ -41,9 +41,16 @@ IXGBE_WRITE_REG(hw, reg, (u32) value); \ IXGBE_WRITE_REG(hw, reg + 4, (u32) (value >> 32)); \ } while (0) +#if !defined(NO_READ_PBA_RAW) || !defined(NO_WRITE_PBA_RAW) +struct ixgbe_pba { + u16 word[2]; + u16 *pba_block; +}; +#endif -u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw); +void ixgbe_dcb_get_rtrup2tc_generic(struct ixgbe_hw *hw, u8 *map); +u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw); 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); @@ -52,8 +59,16 @@ 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_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num, u32 pba_num_size); +s32 ixgbe_read_pba_raw(struct ixgbe_hw *hw, u16 *eeprom_buf, + u32 eeprom_buf_size, u16 max_pba_block_size, + struct ixgbe_pba *pba); +s32 ixgbe_write_pba_raw(struct ixgbe_hw *hw, u16 *eeprom_buf, + u32 eeprom_buf_size, struct ixgbe_pba *pba); +s32 ixgbe_get_pba_block_size(struct ixgbe_hw *hw, u16 *eeprom_buf, + u32 eeprom_buf_size, u16 *pba_block_size); s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr); s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw); +void ixgbe_set_pci_config_data_generic(struct ixgbe_hw *hw, u16 link_status); void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw); s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw); @@ -96,6 +111,7 @@ s32 ixgbe_disable_sec_rx_path_generic(struct ixgbe_hw *hw); s32 ixgbe_enable_sec_rx_path_generic(struct ixgbe_hw *hw); s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw); +bool ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw); void ixgbe_fc_autoneg(struct ixgbe_hw *hw); s32 ixgbe_validate_mac_addr(u8 *mac_addr); @@ -137,5 +153,12 @@ void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb, u32 headroom, void ixgbe_enable_relaxed_ordering_gen2(struct ixgbe_hw *hw); s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, u8 build, u8 ver); +u8 ixgbe_calculate_checksum(u8 *buffer, u32 length); +s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, + u32 length); void ixgbe_clear_tx_pending(struct ixgbe_hw *hw); + +extern s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw); +extern void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw); + #endif /* IXGBE_COMMON */ diff --git a/sys/dev/netif/ix/ixgbe_dcb.c b/sys/dev/netif/ix/ixgbe_dcb.c new file mode 100644 index 0000000000..149aad1234 --- /dev/null +++ b/sys/dev/netif/ix/ixgbe_dcb.c @@ -0,0 +1,718 @@ +/****************************************************************************** + + Copyright (c) 2001-2013, 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$*/ + + +#include "ixgbe_type.h" +#include "ixgbe_dcb.h" +#include "ixgbe_dcb_82598.h" +#include "ixgbe_dcb_82599.h" + +/** + * ixgbe_dcb_calculate_tc_credits - This calculates the ieee traffic class + * credits from the configured bandwidth percentages. Credits + * are the smallest unit programmable into the underlying + * hardware. The IEEE 802.1Qaz specification do not use bandwidth + * groups so this is much simplified from the CEE case. + */ +s32 ixgbe_dcb_calculate_tc_credits(u8 *bw, u16 *refill, u16 *max, + int max_frame_size) +{ + int min_percent = 100; + int min_credit, multiplier; + int i; + + min_credit = ((max_frame_size / 2) + IXGBE_DCB_CREDIT_QUANTUM - 1) / + IXGBE_DCB_CREDIT_QUANTUM; + + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + if (bw[i] < min_percent && bw[i]) + min_percent = bw[i]; + } + + multiplier = (min_credit / min_percent) + 1; + + /* Find out the hw credits for each TC */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + int val = min(bw[i] * multiplier, IXGBE_DCB_MAX_CREDIT_REFILL); + + if (val < min_credit) + val = min_credit; + refill[i] = (u16)val; + + max[i] = bw[i] ? (bw[i]*IXGBE_DCB_MAX_CREDIT)/100 : min_credit; + } + + return 0; +} + +/** + * ixgbe_dcb_calculate_tc_credits_cee - Calculates traffic class credits + * @ixgbe_dcb_config: Struct containing DCB settings. + * @direction: Configuring either Tx or Rx. + * + * This function calculates the credits allocated to each traffic class. + * It should be called only after the rules are checked by + * ixgbe_dcb_check_config_cee(). + */ +s32 ixgbe_dcb_calculate_tc_credits_cee(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config, + u32 max_frame_size, u8 direction) +{ + struct ixgbe_dcb_tc_path *p; + u32 min_multiplier = 0; + u16 min_percent = 100; + s32 ret_val = IXGBE_SUCCESS; + /* Initialization values default for Tx settings */ + u32 min_credit = 0; + u32 credit_refill = 0; + u32 credit_max = 0; + u16 link_percentage = 0; + u8 bw_percent = 0; + u8 i; + + if (dcb_config == NULL) { + ret_val = IXGBE_ERR_CONFIG; + goto out; + } + + min_credit = ((max_frame_size / 2) + IXGBE_DCB_CREDIT_QUANTUM - 1) / + IXGBE_DCB_CREDIT_QUANTUM; + + /* Find smallest link percentage */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[direction]; + bw_percent = dcb_config->bw_percentage[direction][p->bwg_id]; + link_percentage = p->bwg_percent; + + link_percentage = (link_percentage * bw_percent) / 100; + + if (link_percentage && link_percentage < min_percent) + min_percent = link_percentage; + } + + /* + * The ratio between traffic classes will control the bandwidth + * percentages seen on the wire. To calculate this ratio we use + * a multiplier. It is required that the refill credits must be + * larger than the max frame size so here we find the smallest + * multiplier that will allow all bandwidth percentages to be + * greater than the max frame size. + */ + min_multiplier = (min_credit / min_percent) + 1; + + /* Find out the link percentage for each TC first */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[direction]; + bw_percent = dcb_config->bw_percentage[direction][p->bwg_id]; + + link_percentage = p->bwg_percent; + /* Must be careful of integer division for very small nums */ + link_percentage = (link_percentage * bw_percent) / 100; + if (p->bwg_percent > 0 && link_percentage == 0) + link_percentage = 1; + + /* Save link_percentage for reference */ + p->link_percent = (u8)link_percentage; + + /* Calculate credit refill ratio using multiplier */ + credit_refill = min(link_percentage * min_multiplier, + (u32)IXGBE_DCB_MAX_CREDIT_REFILL); + p->data_credits_refill = (u16)credit_refill; + + /* Calculate maximum credit for the TC */ + credit_max = (link_percentage * IXGBE_DCB_MAX_CREDIT) / 100; + + /* + * Adjustment based on rule checking, if the percentage + * of a TC is too small, the maximum credit may not be + * enough to send out a jumbo frame in data plane arbitration. + */ + if (credit_max && (credit_max < min_credit)) + credit_max = min_credit; + + if (direction == IXGBE_DCB_TX_CONFIG) { + /* + * Adjustment based on rule checking, if the + * percentage of a TC is too small, the maximum + * credit may not be enough to send out a TSO + * packet in descriptor plane arbitration. + */ + if (credit_max && (credit_max < + IXGBE_DCB_MIN_TSO_CREDIT) + && (hw->mac.type == ixgbe_mac_82598EB)) + credit_max = IXGBE_DCB_MIN_TSO_CREDIT; + + dcb_config->tc_config[i].desc_credits_max = + (u16)credit_max; + } + + p->data_credits_max = (u16)credit_max; + } + +out: + return ret_val; +} + +/** + * ixgbe_dcb_unpack_pfc_cee - Unpack dcb_config PFC info + * @cfg: dcb configuration to unpack into hardware consumable fields + * @map: user priority to traffic class map + * @pfc_up: u8 to store user priority PFC bitmask + * + * This unpacks the dcb configuration PFC info which is stored per + * traffic class into a 8bit user priority bitmask that can be + * consumed by hardware routines. The priority to tc map must be + * updated before calling this routine to use current up-to maps. + */ +void ixgbe_dcb_unpack_pfc_cee(struct ixgbe_dcb_config *cfg, u8 *map, u8 *pfc_up) +{ + struct ixgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; + int up; + + /* + * If the TC for this user priority has PFC enabled then set the + * matching bit in 'pfc_up' to reflect that PFC is enabled. + */ + for (*pfc_up = 0, up = 0; up < IXGBE_DCB_MAX_USER_PRIORITY; up++) { + if (tc_config[map[up]].pfc != ixgbe_dcb_pfc_disabled) + *pfc_up |= 1 << up; + } +} + +void ixgbe_dcb_unpack_refill_cee(struct ixgbe_dcb_config *cfg, int direction, + u16 *refill) +{ + struct ixgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; + int tc; + + for (tc = 0; tc < IXGBE_DCB_MAX_TRAFFIC_CLASS; tc++) + refill[tc] = tc_config[tc].path[direction].data_credits_refill; +} + +void ixgbe_dcb_unpack_max_cee(struct ixgbe_dcb_config *cfg, u16 *max) +{ + struct ixgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; + int tc; + + for (tc = 0; tc < IXGBE_DCB_MAX_TRAFFIC_CLASS; tc++) + max[tc] = tc_config[tc].desc_credits_max; +} + +void ixgbe_dcb_unpack_bwgid_cee(struct ixgbe_dcb_config *cfg, int direction, + u8 *bwgid) +{ + struct ixgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; + int tc; + + for (tc = 0; tc < IXGBE_DCB_MAX_TRAFFIC_CLASS; tc++) + bwgid[tc] = tc_config[tc].path[direction].bwg_id; +} + +void ixgbe_dcb_unpack_tsa_cee(struct ixgbe_dcb_config *cfg, int direction, + u8 *tsa) +{ + struct ixgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; + int tc; + + for (tc = 0; tc < IXGBE_DCB_MAX_TRAFFIC_CLASS; tc++) + tsa[tc] = tc_config[tc].path[direction].tsa; +} + +u8 ixgbe_dcb_get_tc_from_up(struct ixgbe_dcb_config *cfg, int direction, u8 up) +{ + struct ixgbe_dcb_tc_config *tc_config = &cfg->tc_config[0]; + u8 prio_mask = 1 << up; + u8 tc = cfg->num_tcs.pg_tcs; + + /* If tc is 0 then DCB is likely not enabled or supported */ + if (!tc) + goto out; + + /* + * Test from maximum TC to 1 and report the first match we find. If + * we find no match we can assume that the TC is 0 since the TC must + * be set for all user priorities + */ + for (tc--; tc; tc--) { + if (prio_mask & tc_config[tc].path[direction].up_to_tc_bitmap) + break; + } +out: + return tc; +} + +void ixgbe_dcb_unpack_map_cee(struct ixgbe_dcb_config *cfg, int direction, + u8 *map) +{ + u8 up; + + for (up = 0; up < IXGBE_DCB_MAX_USER_PRIORITY; up++) + map[up] = ixgbe_dcb_get_tc_from_up(cfg, direction, up); +} + +/** + * ixgbe_dcb_config - Struct containing DCB settings. + * @dcb_config: Pointer to DCB config structure + * + * This function checks DCB rules for DCB settings. + * The following rules are checked: + * 1. The sum of bandwidth percentages of all Bandwidth Groups must total 100%. + * 2. The sum of bandwidth percentages of all Traffic Classes within a Bandwidth + * Group must total 100. + * 3. A Traffic Class should not be set to both Link Strict Priority + * and Group Strict Priority. + * 4. Link strict Bandwidth Groups can only have link strict traffic classes + * with zero bandwidth. + */ +s32 ixgbe_dcb_check_config_cee(struct ixgbe_dcb_config *dcb_config) +{ + struct ixgbe_dcb_tc_path *p; + s32 ret_val = IXGBE_SUCCESS; + u8 i, j, bw = 0, bw_id; + u8 bw_sum[2][IXGBE_DCB_MAX_BW_GROUP]; + bool link_strict[2][IXGBE_DCB_MAX_BW_GROUP]; + + memset(bw_sum, 0, sizeof(bw_sum)); + memset(link_strict, 0, sizeof(link_strict)); + + /* First Tx, then Rx */ + for (i = 0; i < 2; i++) { + /* Check each traffic class for rule violation */ + for (j = 0; j < IXGBE_DCB_MAX_TRAFFIC_CLASS; j++) { + p = &dcb_config->tc_config[j].path[i]; + + bw = p->bwg_percent; + bw_id = p->bwg_id; + + if (bw_id >= IXGBE_DCB_MAX_BW_GROUP) { + ret_val = IXGBE_ERR_CONFIG; + goto err_config; + } + if (p->tsa == ixgbe_dcb_tsa_strict) { + link_strict[i][bw_id] = TRUE; + /* Link strict should have zero bandwidth */ + if (bw) { + ret_val = IXGBE_ERR_CONFIG; + goto err_config; + } + } else if (!bw) { + /* + * Traffic classes without link strict + * should have non-zero bandwidth. + */ + ret_val = IXGBE_ERR_CONFIG; + goto err_config; + } + bw_sum[i][bw_id] += bw; + } + + bw = 0; + + /* Check each bandwidth group for rule violation */ + for (j = 0; j < IXGBE_DCB_MAX_BW_GROUP; j++) { + bw += dcb_config->bw_percentage[i][j]; + /* + * Sum of bandwidth percentages of all traffic classes + * within a Bandwidth Group must total 100 except for + * link strict group (zero bandwidth). + */ + if (link_strict[i][j]) { + if (bw_sum[i][j]) { + /* + * Link strict group should have zero + * bandwidth. + */ + ret_val = IXGBE_ERR_CONFIG; + goto err_config; + } + } else if (bw_sum[i][j] != IXGBE_DCB_BW_PERCENT && + bw_sum[i][j] != 0) { + ret_val = IXGBE_ERR_CONFIG; + goto err_config; + } + } + + if (bw != IXGBE_DCB_BW_PERCENT) { + ret_val = IXGBE_ERR_CONFIG; + goto err_config; + } + } + +err_config: + DEBUGOUT2("DCB error code %d while checking %s settings.\n", + ret_val, (i == IXGBE_DCB_TX_CONFIG) ? "Tx" : "Rx"); + + return ret_val; +} + +/** + * ixgbe_dcb_get_tc_stats - Returns status of each traffic class + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the status data for each of the Traffic Classes in use. + */ +s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + s32 ret = IXGBE_NOT_IMPLEMENTED; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_get_tc_stats_82598(hw, stats, tc_count); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ret = ixgbe_dcb_get_tc_stats_82599(hw, stats, tc_count); + break; +#endif + default: + break; + } + return ret; +} + +/** + * ixgbe_dcb_get_pfc_stats - Returns CBFC status of each traffic class + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the CBFC status data for each of the Traffic Classes. + */ +s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + s32 ret = IXGBE_NOT_IMPLEMENTED; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_get_pfc_stats_82598(hw, stats, tc_count); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ret = ixgbe_dcb_get_pfc_stats_82599(hw, stats, tc_count); + break; +#endif + default: + break; + } + return ret; +} + +/** + * ixgbe_dcb_config_rx_arbiter_cee - Config Rx arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Rx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_rx_arbiter_cee(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = IXGBE_NOT_IMPLEMENTED; + u8 tsa[IXGBE_DCB_MAX_TRAFFIC_CLASS] = { 0 }; + u8 bwgid[IXGBE_DCB_MAX_TRAFFIC_CLASS] = { 0 }; + u8 map[IXGBE_DCB_MAX_USER_PRIORITY] = { 0 }; + u16 refill[IXGBE_DCB_MAX_TRAFFIC_CLASS] = { 0 }; + u16 max[IXGBE_DCB_MAX_TRAFFIC_CLASS] = { 0 }; + + ixgbe_dcb_unpack_refill_cee(dcb_config, IXGBE_DCB_TX_CONFIG, refill); + ixgbe_dcb_unpack_max_cee(dcb_config, max); + ixgbe_dcb_unpack_bwgid_cee(dcb_config, IXGBE_DCB_TX_CONFIG, bwgid); + ixgbe_dcb_unpack_tsa_cee(dcb_config, IXGBE_DCB_TX_CONFIG, tsa); + ixgbe_dcb_unpack_map_cee(dcb_config, IXGBE_DCB_TX_CONFIG, map); + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max, tsa); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ret = ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwgid, + tsa, map); + break; +#endif + default: + break; + } + return ret; +} + +/** + * ixgbe_dcb_config_tx_desc_arbiter_cee - Config Tx Desc arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Descriptor Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_desc_arbiter_cee(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = IXGBE_NOT_IMPLEMENTED; + u8 tsa[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + u8 bwgid[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + u16 refill[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + u16 max[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + + ixgbe_dcb_unpack_refill_cee(dcb_config, IXGBE_DCB_TX_CONFIG, refill); + ixgbe_dcb_unpack_max_cee(dcb_config, max); + ixgbe_dcb_unpack_bwgid_cee(dcb_config, IXGBE_DCB_TX_CONFIG, bwgid); + ixgbe_dcb_unpack_tsa_cee(dcb_config, IXGBE_DCB_TX_CONFIG, tsa); + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_config_tx_desc_arbiter_82598(hw, refill, max, + bwgid, tsa); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ret = ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max, + bwgid, tsa); + break; +#endif + default: + break; + } + return ret; +} + +/** + * ixgbe_dcb_config_tx_data_arbiter_cee - Config Tx data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_data_arbiter_cee(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = IXGBE_NOT_IMPLEMENTED; + u8 tsa[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + u8 bwgid[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + u8 map[IXGBE_DCB_MAX_USER_PRIORITY] = { 0 }; + u16 refill[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + u16 max[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + + ixgbe_dcb_unpack_refill_cee(dcb_config, IXGBE_DCB_TX_CONFIG, refill); + ixgbe_dcb_unpack_max_cee(dcb_config, max); + ixgbe_dcb_unpack_bwgid_cee(dcb_config, IXGBE_DCB_TX_CONFIG, bwgid); + ixgbe_dcb_unpack_tsa_cee(dcb_config, IXGBE_DCB_TX_CONFIG, tsa); + ixgbe_dcb_unpack_map_cee(dcb_config, IXGBE_DCB_TX_CONFIG, map); + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_config_tx_data_arbiter_82598(hw, refill, max, + bwgid, tsa); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ret = ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max, + bwgid, tsa, + map); + break; +#endif + default: + break; + } + return ret; +} + +/** + * ixgbe_dcb_config_pfc_cee - Config priority flow control + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Priority Flow Control for each traffic class. + */ +s32 ixgbe_dcb_config_pfc_cee(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = IXGBE_NOT_IMPLEMENTED; + u8 pfc_en; + u8 map[IXGBE_DCB_MAX_USER_PRIORITY] = { 0 }; + + ixgbe_dcb_unpack_map_cee(dcb_config, IXGBE_DCB_TX_CONFIG, map); + ixgbe_dcb_unpack_pfc_cee(dcb_config, map, &pfc_en); + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_config_pfc_82598(hw, pfc_en); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en, map); + break; +#endif + default: + break; + } + return ret; +} + +/** + * ixgbe_dcb_config_tc_stats - Config traffic class statistics + * @hw: pointer to hardware structure + * + * Configure queue statistics registers, all queues belonging to same traffic + * class uses a single set of queue statistics counters. + */ +s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *hw) +{ + s32 ret = IXGBE_NOT_IMPLEMENTED; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_config_tc_stats_82598(hw); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ret = ixgbe_dcb_config_tc_stats_82599(hw, NULL); + break; +#endif + default: + break; + } + return ret; +} + +/** + * ixgbe_dcb_hw_config_cee - Config and enable DCB + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure dcb settings and enable dcb mode. + */ +s32 ixgbe_dcb_hw_config_cee(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = IXGBE_NOT_IMPLEMENTED; + u8 pfc_en; + u8 tsa[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + u8 bwgid[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + u8 map[IXGBE_DCB_MAX_USER_PRIORITY] = { 0 }; + u16 refill[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + u16 max[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + + /* Unpack CEE standard containers */ + ixgbe_dcb_unpack_refill_cee(dcb_config, IXGBE_DCB_TX_CONFIG, refill); + ixgbe_dcb_unpack_max_cee(dcb_config, max); + ixgbe_dcb_unpack_bwgid_cee(dcb_config, IXGBE_DCB_TX_CONFIG, bwgid); + ixgbe_dcb_unpack_tsa_cee(dcb_config, IXGBE_DCB_TX_CONFIG, tsa); + ixgbe_dcb_unpack_map_cee(dcb_config, IXGBE_DCB_TX_CONFIG, map); + + hw->mac.ops.setup_rxpba(hw, dcb_config->num_tcs.pg_tcs, + 0, dcb_config->rx_pba_cfg); + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_hw_config_82598(hw, dcb_config->link_speed, + refill, max, bwgid, tsa); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ixgbe_dcb_config_82599(hw, dcb_config); + ret = ixgbe_dcb_hw_config_82599(hw, dcb_config->link_speed, + refill, max, bwgid, + tsa, map); + + ixgbe_dcb_config_tc_stats_82599(hw, dcb_config); + break; +#endif + default: + break; + } + + if (!ret && dcb_config->pfc_mode_enable) { + ixgbe_dcb_unpack_pfc_cee(dcb_config, map, &pfc_en); + ret = ixgbe_dcb_config_pfc(hw, pfc_en, map); + } + + return ret; +} + +/* Helper routines to abstract HW specifics from DCB netlink ops */ +s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *hw, u8 pfc_en, u8 *map) +{ + int ret = IXGBE_ERR_PARAM; + + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ret = ixgbe_dcb_config_pfc_82598(hw, pfc_en); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en, map); + break; +#endif + default: + break; + } + return ret; +} + +s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, u16 *refill, u16 *max, + u8 *bwg_id, u8 *tsa, u8 *map) +{ + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max, tsa); + ixgbe_dcb_config_tx_desc_arbiter_82598(hw, refill, max, bwg_id, + tsa); + ixgbe_dcb_config_tx_data_arbiter_82598(hw, refill, max, bwg_id, + tsa); + break; + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: +#if !defined(NO_82599_SUPPORT) || !defined(NO_X540_SUPPORT) + ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwg_id, + tsa, map); + ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max, bwg_id, + tsa); + ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max, bwg_id, + tsa, map); + break; +#endif + default: + break; + } + return 0; +} diff --git a/sys/dev/netif/ix/ixgbe_dcb.h b/sys/dev/netif/ix/ixgbe_dcb.h new file mode 100644 index 0000000000..05e548ef98 --- /dev/null +++ b/sys/dev/netif/ix/ixgbe_dcb.h @@ -0,0 +1,176 @@ +/****************************************************************************** + + Copyright (c) 2001-2013, 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$*/ + +#ifndef _IXGBE_DCB_H_ +#define _IXGBE_DCB_H_ + + +#include "ixgbe_type.h" + +/* DCB defines */ +/* DCB credit calculation defines */ +#define IXGBE_DCB_CREDIT_QUANTUM 64 +#define IXGBE_DCB_MAX_CREDIT_REFILL 200 /* 200 * 64B = 12800B */ +#define IXGBE_DCB_MAX_TSO_SIZE (32 * 1024) /* Max TSO pkt size in DCB*/ +#define IXGBE_DCB_MAX_CREDIT (2 * IXGBE_DCB_MAX_CREDIT_REFILL) + +/* 513 for 32KB TSO packet */ +#define IXGBE_DCB_MIN_TSO_CREDIT \ + ((IXGBE_DCB_MAX_TSO_SIZE / IXGBE_DCB_CREDIT_QUANTUM) + 1) + +/* DCB configuration defines */ +#define IXGBE_DCB_MAX_USER_PRIORITY 8 +#define IXGBE_DCB_MAX_BW_GROUP 8 +#define IXGBE_DCB_BW_PERCENT 100 + +#define IXGBE_DCB_TX_CONFIG 0 +#define IXGBE_DCB_RX_CONFIG 1 + +/* DCB capability defines */ +#define IXGBE_DCB_PG_SUPPORT 0x00000001 +#define IXGBE_DCB_PFC_SUPPORT 0x00000002 +#define IXGBE_DCB_BCN_SUPPORT 0x00000004 +#define IXGBE_DCB_UP2TC_SUPPORT 0x00000008 +#define IXGBE_DCB_GSP_SUPPORT 0x00000010 + +struct ixgbe_dcb_support { + u32 capabilities; /* DCB capabilities */ + + /* Each bit represents a number of TCs configurable in the hw. + * If 8 traffic classes can be configured, the value is 0x80. */ + u8 traffic_classes; + u8 pfc_traffic_classes; +}; + +enum ixgbe_dcb_tsa { + ixgbe_dcb_tsa_ets = 0, + ixgbe_dcb_tsa_group_strict_cee, + ixgbe_dcb_tsa_strict +}; + +/* Traffic class bandwidth allocation per direction */ +struct ixgbe_dcb_tc_path { + u8 bwg_id; /* Bandwidth Group (BWG) ID */ + u8 bwg_percent; /* % of BWG's bandwidth */ + u8 link_percent; /* % of link bandwidth */ + u8 up_to_tc_bitmap; /* User Priority to Traffic Class mapping */ + u16 data_credits_refill; /* Credit refill amount in 64B granularity */ + u16 data_credits_max; /* Max credits for a configured packet buffer + * in 64B granularity.*/ + enum ixgbe_dcb_tsa tsa; /* Link or Group Strict Priority */ +}; + +enum ixgbe_dcb_pfc { + ixgbe_dcb_pfc_disabled = 0, + ixgbe_dcb_pfc_enabled, + ixgbe_dcb_pfc_enabled_txonly, + ixgbe_dcb_pfc_enabled_rxonly +}; + +/* Traffic class configuration */ +struct ixgbe_dcb_tc_config { + struct ixgbe_dcb_tc_path path[2]; /* One each for Tx/Rx */ + enum ixgbe_dcb_pfc pfc; /* Class based flow control setting */ + + u16 desc_credits_max; /* For Tx Descriptor arbitration */ + u8 tc; /* Traffic class (TC) */ +}; + +enum ixgbe_dcb_pba { + /* PBA[0-7] each use 64KB FIFO */ + ixgbe_dcb_pba_equal = PBA_STRATEGY_EQUAL, + /* PBA[0-3] each use 80KB, PBA[4-7] each use 48KB */ + ixgbe_dcb_pba_80_48 = PBA_STRATEGY_WEIGHTED +}; + +struct ixgbe_dcb_num_tcs { + u8 pg_tcs; + u8 pfc_tcs; +}; + +struct ixgbe_dcb_config { + struct ixgbe_dcb_tc_config tc_config[IXGBE_DCB_MAX_TRAFFIC_CLASS]; + struct ixgbe_dcb_support support; + struct ixgbe_dcb_num_tcs num_tcs; + u8 bw_percentage[2][IXGBE_DCB_MAX_BW_GROUP]; /* One each for Tx/Rx */ + bool pfc_mode_enable; + bool round_robin_enable; + + enum ixgbe_dcb_pba rx_pba_cfg; + + u32 dcb_cfg_version; /* Not used...OS-specific? */ + u32 link_speed; /* For bandwidth allocation validation purpose */ + bool vt_mode; +}; + +/* DCB driver APIs */ + +/* DCB rule checking */ +s32 ixgbe_dcb_check_config_cee(struct ixgbe_dcb_config *); + +/* DCB credits calculation */ +s32 ixgbe_dcb_calculate_tc_credits(u8 *, u16 *, u16 *, int); +s32 ixgbe_dcb_calculate_tc_credits_cee(struct ixgbe_hw *, + struct ixgbe_dcb_config *, u32, u8); + +/* DCB PFC */ +s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *, u8, u8 *); +s32 ixgbe_dcb_config_pfc_cee(struct ixgbe_hw *, struct ixgbe_dcb_config *); + +/* DCB stats */ +s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *); +s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8); +s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8); + +/* DCB config arbiters */ +s32 ixgbe_dcb_config_tx_desc_arbiter_cee(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_tx_data_arbiter_cee(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_rx_arbiter_cee(struct ixgbe_hw *, + struct ixgbe_dcb_config *); + +/* DCB unpack routines */ +void ixgbe_dcb_unpack_pfc_cee(struct ixgbe_dcb_config *, u8 *, u8 *); +void ixgbe_dcb_unpack_refill_cee(struct ixgbe_dcb_config *, int, u16 *); +void ixgbe_dcb_unpack_max_cee(struct ixgbe_dcb_config *, u16 *); +void ixgbe_dcb_unpack_bwgid_cee(struct ixgbe_dcb_config *, int, u8 *); +void ixgbe_dcb_unpack_tsa_cee(struct ixgbe_dcb_config *, int, u8 *); +void ixgbe_dcb_unpack_map_cee(struct ixgbe_dcb_config *, int, u8 *); +u8 ixgbe_dcb_get_tc_from_up(struct ixgbe_dcb_config *, int, u8); + +/* DCB initialization */ +s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, u16 *, u16 *, u8 *, u8 *, u8 *); +s32 ixgbe_dcb_hw_config_cee(struct ixgbe_hw *, struct ixgbe_dcb_config *); +#endif /* _IXGBE_DCB_H_ */ diff --git a/sys/dev/netif/ix/ixgbe_dcb_82598.c b/sys/dev/netif/ix/ixgbe_dcb_82598.c new file mode 100644 index 0000000000..aee808f83a --- /dev/null +++ b/sys/dev/netif/ix/ixgbe_dcb_82598.c @@ -0,0 +1,359 @@ +/****************************************************************************** + + Copyright (c) 2001-2013, 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$*/ + + +#include "ixgbe_type.h" +#include "ixgbe_dcb.h" +#include "ixgbe_dcb_82598.h" + +/** + * ixgbe_dcb_get_tc_stats_82598 - Return status data for each traffic class + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the status data for each of the Traffic Classes in use. + */ +s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *hw, + struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + int tc; + + DEBUGFUNC("dcb_get_tc_stats"); + + if (tc_count > IXGBE_DCB_MAX_TRAFFIC_CLASS) + return IXGBE_ERR_PARAM; + + /* Statistics pertaining to each traffic class */ + for (tc = 0; tc < tc_count; tc++) { + /* Transmitted Packets */ + stats->qptc[tc] += IXGBE_READ_REG(hw, IXGBE_QPTC(tc)); + /* Transmitted Bytes */ + stats->qbtc[tc] += IXGBE_READ_REG(hw, IXGBE_QBTC(tc)); + /* Received Packets */ + stats->qprc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRC(tc)); + /* Received Bytes */ + stats->qbrc[tc] += IXGBE_READ_REG(hw, IXGBE_QBRC(tc)); + +#if 0 + /* Can we get rid of these?? Consequently, getting rid + * of the tc_stats structure. + */ + tc_stats_array[up]->in_overflow_discards = 0; + tc_stats_array[up]->out_overflow_discards = 0; +#endif + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_get_pfc_stats_82598 - Returns CBFC status data + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the CBFC status data for each of the Traffic Classes. + */ +s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *hw, + struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + int tc; + + DEBUGFUNC("dcb_get_pfc_stats"); + + if (tc_count > IXGBE_DCB_MAX_TRAFFIC_CLASS) + return IXGBE_ERR_PARAM; + + for (tc = 0; tc < tc_count; tc++) { + /* Priority XOFF Transmitted */ + stats->pxofftxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(tc)); + /* Priority XOFF Received */ + stats->pxoffrxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(tc)); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_rx_arbiter_82598 - Config Rx data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Rx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *tsa) +{ + u32 reg = 0; + u32 credit_refill = 0; + u32 credit_max = 0; + u8 i = 0; + + reg = IXGBE_READ_REG(hw, IXGBE_RUPPBMR) | IXGBE_RUPPBMR_MQA; + IXGBE_WRITE_REG(hw, IXGBE_RUPPBMR, reg); + + reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + /* Enable Arbiter */ + reg &= ~IXGBE_RMCS_ARBDIS; + /* Enable Receive Recycle within the BWG */ + reg |= IXGBE_RMCS_RRM; + /* Enable Deficit Fixed Priority arbitration*/ + reg |= IXGBE_RMCS_DFP; + + IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + credit_refill = refill[i]; + credit_max = max[i]; + + reg = credit_refill | (credit_max << IXGBE_RT2CR_MCL_SHIFT); + + if (tsa[i] == ixgbe_dcb_tsa_strict) + reg |= IXGBE_RT2CR_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_RT2CR(i), reg); + } + + reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + reg |= IXGBE_RDRXCTL_RDMTS_1_2; + reg |= IXGBE_RDRXCTL_MPBEN; + reg |= IXGBE_RDRXCTL_MCEN; + IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg); + + reg = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + /* Make sure there is enough descriptors before arbitration */ + reg &= ~IXGBE_RXCTRL_DMBYPS; + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_tx_desc_arbiter_82598 - Config Tx Desc. arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Descriptor Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, + u16 *refill, u16 *max, u8 *bwg_id, + u8 *tsa) +{ + u32 reg, max_credits; + u8 i; + + reg = IXGBE_READ_REG(hw, IXGBE_DPMCS); + + /* Enable arbiter */ + reg &= ~IXGBE_DPMCS_ARBDIS; + reg |= IXGBE_DPMCS_TSOEF; + + /* Configure Max TSO packet size 34KB including payload and headers */ + reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT); + + IXGBE_WRITE_REG(hw, IXGBE_DPMCS, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + max_credits = max[i]; + reg = max_credits << IXGBE_TDTQ2TCCR_MCL_SHIFT; + reg |= refill[i]; + reg |= (u32)(bwg_id[i]) << IXGBE_TDTQ2TCCR_BWG_SHIFT; + + if (tsa[i] == ixgbe_dcb_tsa_group_strict_cee) + reg |= IXGBE_TDTQ2TCCR_GSP; + + if (tsa[i] == ixgbe_dcb_tsa_strict) + reg |= IXGBE_TDTQ2TCCR_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_TDTQ2TCCR(i), reg); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_tx_data_arbiter_82598 - Config Tx data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, + u16 *refill, u16 *max, u8 *bwg_id, + u8 *tsa) +{ + u32 reg; + u8 i; + + reg = IXGBE_READ_REG(hw, IXGBE_PDPMCS); + /* Enable Data Plane Arbiter */ + reg &= ~IXGBE_PDPMCS_ARBDIS; + /* Enable DFP and Transmit Recycle Mode */ + reg |= (IXGBE_PDPMCS_TPPAC | IXGBE_PDPMCS_TRM); + + IXGBE_WRITE_REG(hw, IXGBE_PDPMCS, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + reg = refill[i]; + reg |= (u32)(max[i]) << IXGBE_TDPT2TCCR_MCL_SHIFT; + reg |= (u32)(bwg_id[i]) << IXGBE_TDPT2TCCR_BWG_SHIFT; + + if (tsa[i] == ixgbe_dcb_tsa_group_strict_cee) + reg |= IXGBE_TDPT2TCCR_GSP; + + if (tsa[i] == ixgbe_dcb_tsa_strict) + reg |= IXGBE_TDPT2TCCR_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_TDPT2TCCR(i), reg); + } + + /* Enable Tx packet buffer division */ + reg = IXGBE_READ_REG(hw, IXGBE_DTXCTL); + reg |= IXGBE_DTXCTL_ENDBUBD; + IXGBE_WRITE_REG(hw, IXGBE_DTXCTL, reg); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_pfc_82598 - Config priority flow control + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Priority Flow Control for each traffic class. + */ +s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en) +{ + u32 fcrtl, reg; + u8 i; + + /* Enable Transmit Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + reg &= ~IXGBE_RMCS_TFCE_802_3X; + reg |= IXGBE_RMCS_TFCE_PRIORITY; + IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); + + /* Enable Receive Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); + reg &= ~(IXGBE_FCTRL_RPFCE | IXGBE_FCTRL_RFCE); + + if (pfc_en) + reg |= IXGBE_FCTRL_RPFCE; + + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg); + + /* Configure PFC Tx thresholds per TC */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + if (!(pfc_en & (1 << i))) { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), 0); + continue; + } + + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; + reg = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), fcrtl); + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg); + } + + /* Configure pause time */ + reg = hw->fc.pause_time | (hw->fc.pause_time << 16); + for (i = 0; i < (IXGBE_DCB_MAX_TRAFFIC_CLASS / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); + + /* Configure flow control refresh threshold value */ + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_tc_stats_82598 - Configure traffic class statistics + * @hw: pointer to hardware structure + * + * Configure queue statistics registers, all queues belonging to same traffic + * class uses a single set of queue statistics counters. + */ +s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) +{ + u32 reg = 0; + u8 i = 0; + u8 j = 0; + + /* Receive Queues stats setting - 8 queues per statistics reg */ + for (i = 0, j = 0; i < 15 && j < 8; i = i + 2, j++) { + reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i)); + reg |= ((0x1010101) * j); + IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), reg); + reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i + 1)); + reg |= ((0x1010101) * j); + IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i + 1), reg); + } + /* Transmit Queues stats setting - 4 queues per statistics reg*/ + for (i = 0; i < 8; i++) { + reg = IXGBE_READ_REG(hw, IXGBE_TQSMR(i)); + reg |= ((0x1010101) * i); + IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i), reg); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_hw_config_82598 - Config and enable DCB + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure dcb settings and enable dcb mode. + */ +s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, int link_speed, + u16 *refill, u16 *max, u8 *bwg_id, + u8 *tsa) +{ + ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max, tsa); + ixgbe_dcb_config_tx_desc_arbiter_82598(hw, refill, max, bwg_id, + tsa); + ixgbe_dcb_config_tx_data_arbiter_82598(hw, refill, max, bwg_id, + tsa); + ixgbe_dcb_config_tc_stats_82598(hw); + + + return IXGBE_SUCCESS; +} diff --git a/sys/dev/netif/ix/ixgbe_dcb_82598.h b/sys/dev/netif/ix/ixgbe_dcb_82598.h new file mode 100644 index 0000000000..9b634a3aa5 --- /dev/null +++ b/sys/dev/netif/ix/ixgbe_dcb_82598.h @@ -0,0 +1,100 @@ +/****************************************************************************** + + Copyright (c) 2001-2013, 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$*/ + +#ifndef _IXGBE_DCB_82598_H_ +#define _IXGBE_DCB_82598_H_ + +/* DCB register definitions */ + +#define IXGBE_DPMCS_MTSOS_SHIFT 16 +#define IXGBE_DPMCS_TDPAC 0x00000001 /* 0 Round Robin, + * 1 DFP - Deficit Fixed Priority */ +#define IXGBE_DPMCS_TRM 0x00000010 /* Transmit Recycle Mode */ +#define IXGBE_DPMCS_ARBDIS 0x00000040 /* DCB arbiter disable */ +#define IXGBE_DPMCS_TSOEF 0x00080000 /* TSO Expand Factor: 0=x4, 1=x2 */ + +#define IXGBE_RUPPBMR_MQA 0x80000000 /* Enable UP to queue mapping */ + +#define IXGBE_RT2CR_MCL_SHIFT 12 /* Offset to Max Credit Limit setting */ +#define IXGBE_RT2CR_LSP 0x80000000 /* LSP enable bit */ + +#define IXGBE_RDRXCTL_MPBEN 0x00000010 /* DMA config for multiple packet + * buffers enable */ +#define IXGBE_RDRXCTL_MCEN 0x00000040 /* DMA config for multiple cores + * (RSS) enable */ + +#define IXGBE_TDTQ2TCCR_MCL_SHIFT 12 +#define IXGBE_TDTQ2TCCR_BWG_SHIFT 9 +#define IXGBE_TDTQ2TCCR_GSP 0x40000000 +#define IXGBE_TDTQ2TCCR_LSP 0x80000000 + +#define IXGBE_TDPT2TCCR_MCL_SHIFT 12 +#define IXGBE_TDPT2TCCR_BWG_SHIFT 9 +#define IXGBE_TDPT2TCCR_GSP 0x40000000 +#define IXGBE_TDPT2TCCR_LSP 0x80000000 + +#define IXGBE_PDPMCS_TPPAC 0x00000020 /* 0 Round Robin, + * 1 DFP - Deficit Fixed Priority */ +#define IXGBE_PDPMCS_ARBDIS 0x00000040 /* Arbiter disable */ +#define IXGBE_PDPMCS_TRM 0x00000100 /* Transmit Recycle Mode enable */ + +#define IXGBE_DTXCTL_ENDBUBD 0x00000004 /* Enable DBU buffer division */ + +#define IXGBE_TXPBSIZE_40KB 0x0000A000 /* 40KB Packet Buffer */ +#define IXGBE_RXPBSIZE_48KB 0x0000C000 /* 48KB Packet Buffer */ +#define IXGBE_RXPBSIZE_64KB 0x00010000 /* 64KB Packet Buffer */ +#define IXGBE_RXPBSIZE_80KB 0x00014000 /* 80KB Packet Buffer */ + +/* DCB driver APIs */ + +/* DCB PFC */ +s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, u8); + +/* DCB stats */ +s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *); +s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *, + struct ixgbe_hw_stats *, u8); +s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *, + struct ixgbe_hw_stats *, u8); + +/* DCB config arbiters */ +s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *, u16 *, u16 *, + u8 *, u8 *); +s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *, u16 *, u16 *, + u8 *, u8 *); +s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *, u16 *, u16 *, u8 *); + +/* DCB initialization */ +s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *, int, u16 *, u16 *, u8 *, u8 *); +#endif /* _IXGBE_DCB_82958_H_ */ diff --git a/sys/dev/netif/ix/ixgbe_dcb_82599.c b/sys/dev/netif/ix/ixgbe_dcb_82599.c new file mode 100644 index 0000000000..085ca0ce14 --- /dev/null +++ b/sys/dev/netif/ix/ixgbe_dcb_82599.c @@ -0,0 +1,586 @@ +/****************************************************************************** + + Copyright (c) 2001-2013, 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$*/ + + +#include "ixgbe_type.h" +#include "ixgbe_dcb.h" +#include "ixgbe_dcb_82599.h" + +/** + * ixgbe_dcb_get_tc_stats_82599 - Returns status for each traffic class + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the status data for each of the Traffic Classes in use. + */ +s32 ixgbe_dcb_get_tc_stats_82599(struct ixgbe_hw *hw, + struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + int tc; + + DEBUGFUNC("dcb_get_tc_stats"); + + if (tc_count > IXGBE_DCB_MAX_TRAFFIC_CLASS) + return IXGBE_ERR_PARAM; + + /* Statistics pertaining to each traffic class */ + for (tc = 0; tc < tc_count; tc++) { + /* Transmitted Packets */ + stats->qptc[tc] += IXGBE_READ_REG(hw, IXGBE_QPTC(tc)); + /* Transmitted Bytes (read low first to prevent missed carry) */ + stats->qbtc[tc] += IXGBE_READ_REG(hw, IXGBE_QBTC_L(tc)); + stats->qbtc[tc] += + (((u64)(IXGBE_READ_REG(hw, IXGBE_QBTC_H(tc)))) << 32); + /* Received Packets */ + stats->qprc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRC(tc)); + /* Received Bytes (read low first to prevent missed carry) */ + stats->qbrc[tc] += IXGBE_READ_REG(hw, IXGBE_QBRC_L(tc)); + stats->qbrc[tc] += + (((u64)(IXGBE_READ_REG(hw, IXGBE_QBRC_H(tc)))) << 32); + + /* Received Dropped Packet */ + stats->qprdc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRDC(tc)); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_get_pfc_stats_82599 - Return CBFC status data + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the CBFC status data for each of the Traffic Classes. + */ +s32 ixgbe_dcb_get_pfc_stats_82599(struct ixgbe_hw *hw, + struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + int tc; + + DEBUGFUNC("dcb_get_pfc_stats"); + + if (tc_count > IXGBE_DCB_MAX_TRAFFIC_CLASS) + return IXGBE_ERR_PARAM; + + for (tc = 0; tc < tc_count; tc++) { + /* Priority XOFF Transmitted */ + stats->pxofftxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(tc)); + /* Priority XOFF Received */ + stats->pxoffrxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXCNT(tc)); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_rx_arbiter_82599 - Config Rx Data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Rx Packet Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *tsa, + u8 *map) +{ + u32 reg = 0; + u32 credit_refill = 0; + u32 credit_max = 0; + u8 i = 0; + + /* + * Disable the arbiter before changing parameters + * (always enable recycle mode; WSP) + */ + reg = IXGBE_RTRPCS_RRM | IXGBE_RTRPCS_RAC | IXGBE_RTRPCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTRPCS, reg); + + /* + * map all UPs to TCs. up_to_tc_bitmap for each TC has corresponding + * bits sets for the UPs that needs to be mappped to that TC. + * e.g if priorities 6 and 7 are to be mapped to a TC then the + * up_to_tc_bitmap value for that TC will be 11000000 in binary. + */ + reg = 0; + for (i = 0; i < IXGBE_DCB_MAX_USER_PRIORITY; i++) + reg |= (map[i] << (i * IXGBE_RTRUP2TC_UP_SHIFT)); + + IXGBE_WRITE_REG(hw, IXGBE_RTRUP2TC, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + credit_refill = refill[i]; + credit_max = max[i]; + reg = credit_refill | (credit_max << IXGBE_RTRPT4C_MCL_SHIFT); + + reg |= (u32)(bwg_id[i]) << IXGBE_RTRPT4C_BWG_SHIFT; + + if (tsa[i] == ixgbe_dcb_tsa_strict) + reg |= IXGBE_RTRPT4C_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_RTRPT4C(i), reg); + } + + /* + * Configure Rx packet plane (recycle mode; WSP) and + * enable arbiter + */ + reg = IXGBE_RTRPCS_RRM | IXGBE_RTRPCS_RAC; + IXGBE_WRITE_REG(hw, IXGBE_RTRPCS, reg); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_tx_desc_arbiter_82599 - Config Tx Desc. arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Descriptor Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *tsa) +{ + u32 reg, max_credits; + u8 i; + + /* Clear the per-Tx queue credits; we use per-TC instead */ + for (i = 0; i < 128; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, i); + IXGBE_WRITE_REG(hw, IXGBE_RTTDT1C, 0); + } + + /* Configure traffic class credits and priority */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + max_credits = max[i]; + reg = max_credits << IXGBE_RTTDT2C_MCL_SHIFT; + reg |= refill[i]; + reg |= (u32)(bwg_id[i]) << IXGBE_RTTDT2C_BWG_SHIFT; + + if (tsa[i] == ixgbe_dcb_tsa_group_strict_cee) + reg |= IXGBE_RTTDT2C_GSP; + + if (tsa[i] == ixgbe_dcb_tsa_strict) + reg |= IXGBE_RTTDT2C_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_RTTDT2C(i), reg); + } + + /* + * Configure Tx descriptor plane (recycle mode; WSP) and + * enable arbiter + */ + reg = IXGBE_RTTDCS_TDPAC | IXGBE_RTTDCS_TDRM; + IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_tx_data_arbiter_82599 - Config Tx Data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Packet Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw, u16 *refill, + u16 *max, u8 *bwg_id, u8 *tsa, + u8 *map) +{ + u32 reg; + u8 i; + + /* + * Disable the arbiter before changing parameters + * (always enable recycle mode; SP; arb delay) + */ + reg = IXGBE_RTTPCS_TPPAC | IXGBE_RTTPCS_TPRM | + (IXGBE_RTTPCS_ARBD_DCB << IXGBE_RTTPCS_ARBD_SHIFT) | + IXGBE_RTTPCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTPCS, reg); + + /* + * map all UPs to TCs. up_to_tc_bitmap for each TC has corresponding + * bits sets for the UPs that needs to be mappped to that TC. + * e.g if priorities 6 and 7 are to be mapped to a TC then the + * up_to_tc_bitmap value for that TC will be 11000000 in binary. + */ + reg = 0; + for (i = 0; i < IXGBE_DCB_MAX_USER_PRIORITY; i++) + reg |= (map[i] << (i * IXGBE_RTTUP2TC_UP_SHIFT)); + + IXGBE_WRITE_REG(hw, IXGBE_RTTUP2TC, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + reg = refill[i]; + reg |= (u32)(max[i]) << IXGBE_RTTPT2C_MCL_SHIFT; + reg |= (u32)(bwg_id[i]) << IXGBE_RTTPT2C_BWG_SHIFT; + + if (tsa[i] == ixgbe_dcb_tsa_group_strict_cee) + reg |= IXGBE_RTTPT2C_GSP; + + if (tsa[i] == ixgbe_dcb_tsa_strict) + reg |= IXGBE_RTTPT2C_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_RTTPT2C(i), reg); + } + + /* + * Configure Tx packet plane (recycle mode; SP; arb delay) and + * enable arbiter + */ + reg = IXGBE_RTTPCS_TPPAC | IXGBE_RTTPCS_TPRM | + (IXGBE_RTTPCS_ARBD_DCB << IXGBE_RTTPCS_ARBD_SHIFT); + IXGBE_WRITE_REG(hw, IXGBE_RTTPCS, reg); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_pfc_82599 - Configure priority flow control + * @hw: pointer to hardware structure + * @pfc_en: enabled pfc bitmask + * @map: priority to tc assignments indexed by priority + * + * Configure Priority Flow Control (PFC) for each traffic class. + */ +s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en, u8 *map) +{ + u32 i, j, fcrtl, reg; + u8 max_tc = 0; + + /* Enable Transmit Priority Flow Control */ + IXGBE_WRITE_REG(hw, IXGBE_FCCFG, IXGBE_FCCFG_TFCE_PRIORITY); + + /* Enable Receive Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); + reg |= IXGBE_MFLCN_DPF; + + /* + * X540 supports per TC Rx priority flow control. So + * clear all TCs and only enable those that should be + * enabled. + */ + reg &= ~(IXGBE_MFLCN_RPFCE_MASK | IXGBE_MFLCN_RFCE); + + if (hw->mac.type == ixgbe_mac_X540) + reg |= pfc_en << IXGBE_MFLCN_RPFCE_SHIFT; + + if (pfc_en) + reg |= IXGBE_MFLCN_RPFCE; + + IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg); + + for (i = 0; i < IXGBE_DCB_MAX_USER_PRIORITY; i++) { + if (map[i] > max_tc) + max_tc = map[i]; + } + + + /* Configure PFC Tx thresholds per TC */ + for (i = 0; i <= max_tc; i++) { + int enabled = 0; + + for (j = 0; j < IXGBE_DCB_MAX_USER_PRIORITY; j++) { + if ((map[j] == i) && (pfc_en & (1 << j))) { + enabled = 1; + break; + } + } + + if (enabled) { + reg = (hw->fc.high_water[i] << 10) | IXGBE_FCRTH_FCEN; + fcrtl = (hw->fc.low_water[i] << 10) | IXGBE_FCRTL_XONE; + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), fcrtl); + } else { + reg = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i)) - 32; + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), 0); + } + + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), reg); + } + + for (; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), 0); + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), 0); + } + + /* Configure pause time (2 TCs per register) */ + reg = hw->fc.pause_time | (hw->fc.pause_time << 16); + for (i = 0; i < (IXGBE_DCB_MAX_TRAFFIC_CLASS / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); + + /* Configure flow control refresh threshold value */ + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_tc_stats_82599 - Config traffic class statistics + * @hw: pointer to hardware structure + * + * Configure queue statistics registers, all queues belonging to same traffic + * class uses a single set of queue statistics counters. + */ +s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + u32 reg = 0; + u8 i = 0; + u8 tc_count = 8; + bool vt_mode = FALSE; + + if (dcb_config != NULL) { + tc_count = dcb_config->num_tcs.pg_tcs; + vt_mode = dcb_config->vt_mode; + } + + if (!((tc_count == 8 && vt_mode == FALSE) || tc_count == 4)) + return IXGBE_ERR_PARAM; + + if (tc_count == 8 && vt_mode == FALSE) { + /* + * Receive Queues stats setting + * 32 RQSMR registers, each configuring 4 queues. + * + * Set all 16 queues of each TC to the same stat + * with TC 'n' going to stat 'n'. + */ + for (i = 0; i < 32; i++) { + reg = 0x01010101 * (i / 4); + IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), reg); + } + /* + * Transmit Queues stats setting + * 32 TQSM registers, each controlling 4 queues. + * + * Set all queues of each TC to the same stat + * with TC 'n' going to stat 'n'. + * Tx queues are allocated non-uniformly to TCs: + * 32, 32, 16, 16, 8, 8, 8, 8. + */ + for (i = 0; i < 32; i++) { + if (i < 8) + reg = 0x00000000; + else if (i < 16) + reg = 0x01010101; + else if (i < 20) + reg = 0x02020202; + else if (i < 24) + reg = 0x03030303; + else if (i < 26) + reg = 0x04040404; + else if (i < 28) + reg = 0x05050505; + else if (i < 30) + reg = 0x06060606; + else + reg = 0x07070707; + IXGBE_WRITE_REG(hw, IXGBE_TQSM(i), reg); + } + } else if (tc_count == 4 && vt_mode == FALSE) { + /* + * Receive Queues stats setting + * 32 RQSMR registers, each configuring 4 queues. + * + * Set all 16 queues of each TC to the same stat + * with TC 'n' going to stat 'n'. + */ + for (i = 0; i < 32; i++) { + if (i % 8 > 3) + /* In 4 TC mode, odd 16-queue ranges are + * not used. + */ + continue; + reg = 0x01010101 * (i / 8); + IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), reg); + } + /* + * Transmit Queues stats setting + * 32 TQSM registers, each controlling 4 queues. + * + * Set all queues of each TC to the same stat + * with TC 'n' going to stat 'n'. + * Tx queues are allocated non-uniformly to TCs: + * 64, 32, 16, 16. + */ + for (i = 0; i < 32; i++) { + if (i < 16) + reg = 0x00000000; + else if (i < 24) + reg = 0x01010101; + else if (i < 28) + reg = 0x02020202; + else + reg = 0x03030303; + IXGBE_WRITE_REG(hw, IXGBE_TQSM(i), reg); + } + } else if (tc_count == 4 && vt_mode == TRUE) { + /* + * Receive Queues stats setting + * 32 RQSMR registers, each configuring 4 queues. + * + * Queue Indexing in 32 VF with DCB mode maps 4 TC's to each + * pool. Set all 32 queues of each TC across pools to the same + * stat with TC 'n' going to stat 'n'. + */ + for (i = 0; i < 32; i++) + IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), 0x03020100); + /* + * Transmit Queues stats setting + * 32 TQSM registers, each controlling 4 queues. + * + * Queue Indexing in 32 VF with DCB mode maps 4 TC's to each + * pool. Set all 32 queues of each TC across pools to the same + * stat with TC 'n' going to stat 'n'. + */ + for (i = 0; i < 32; i++) + IXGBE_WRITE_REG(hw, IXGBE_TQSM(i), 0x03020100); + } + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_config_82599 - Configure general DCB parameters + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure general DCB parameters. + */ +s32 ixgbe_dcb_config_82599(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + u32 reg; + u32 q; + + /* Disable the Tx desc arbiter so that MTQC can be changed */ + reg = IXGBE_READ_REG(hw, IXGBE_RTTDCS); + reg |= IXGBE_RTTDCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg); + + reg = IXGBE_READ_REG(hw, IXGBE_MRQC); + if (dcb_config->num_tcs.pg_tcs == 8) { + /* Enable DCB for Rx with 8 TCs */ + switch (reg & IXGBE_MRQC_MRQE_MASK) { + case 0: + case IXGBE_MRQC_RT4TCEN: + /* RSS disabled cases */ + reg = (reg & ~IXGBE_MRQC_MRQE_MASK) | + IXGBE_MRQC_RT8TCEN; + break; + case IXGBE_MRQC_RSSEN: + case IXGBE_MRQC_RTRSS4TCEN: + /* RSS enabled cases */ + reg = (reg & ~IXGBE_MRQC_MRQE_MASK) | + IXGBE_MRQC_RTRSS8TCEN; + break; + default: + /* + * Unsupported value, assume stale data, + * overwrite no RSS + */ + ASSERT(0); + reg = (reg & ~IXGBE_MRQC_MRQE_MASK) | + IXGBE_MRQC_RT8TCEN; + } + } + if (dcb_config->num_tcs.pg_tcs == 4) { + /* We support both VT-on and VT-off with 4 TCs. */ + if (dcb_config->vt_mode) + reg = (reg & ~IXGBE_MRQC_MRQE_MASK) | + IXGBE_MRQC_VMDQRT4TCEN; + else + reg = (reg & ~IXGBE_MRQC_MRQE_MASK) | + IXGBE_MRQC_RTRSS4TCEN; + } + IXGBE_WRITE_REG(hw, IXGBE_MRQC, reg); + + /* Enable DCB for Tx with 8 TCs */ + if (dcb_config->num_tcs.pg_tcs == 8) + reg = IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ; + else { + /* We support both VT-on and VT-off with 4 TCs. */ + reg = IXGBE_MTQC_RT_ENA | IXGBE_MTQC_4TC_4TQ; + if (dcb_config->vt_mode) + reg |= IXGBE_MTQC_VT_ENA; + } + IXGBE_WRITE_REG(hw, IXGBE_MTQC, reg); + + /* Disable drop for all queues */ + for (q = 0; q < 128; q++) + IXGBE_WRITE_REG(hw, IXGBE_QDE, + (IXGBE_QDE_WRITE | (q << IXGBE_QDE_IDX_SHIFT))); + + /* Enable the Tx desc arbiter */ + reg = IXGBE_READ_REG(hw, IXGBE_RTTDCS); + reg &= ~IXGBE_RTTDCS_ARBDIS; + IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg); + + /* Enable Security TX Buffer IFG for DCB */ + reg = IXGBE_READ_REG(hw, IXGBE_SECTXMINIFG); + reg |= IXGBE_SECTX_DCB; + IXGBE_WRITE_REG(hw, IXGBE_SECTXMINIFG, reg); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_dcb_hw_config_82599 - Configure and enable DCB + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure dcb settings and enable dcb mode. + */ +s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw, int link_speed, + u16 *refill, u16 *max, u8 *bwg_id, u8 *tsa, + u8 *map) +{ + + ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, bwg_id, tsa, + map); + ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max, bwg_id, + tsa); + ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max, bwg_id, + tsa, map); + + return IXGBE_SUCCESS; +} + diff --git a/sys/dev/netif/ix/ixgbe_dcb_82599.h b/sys/dev/netif/ix/ixgbe_dcb_82599.h new file mode 100644 index 0000000000..91428c0ff3 --- /dev/null +++ b/sys/dev/netif/ix/ixgbe_dcb_82599.h @@ -0,0 +1,154 @@ +/****************************************************************************** + + Copyright (c) 2001-2013, 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$*/ + +#ifndef _IXGBE_DCB_82599_H_ +#define _IXGBE_DCB_82599_H_ + +/* DCB register definitions */ +#define IXGBE_RTTDCS_TDPAC 0x00000001 /* 0 Round Robin, + * 1 WSP - Weighted Strict Priority + */ +#define IXGBE_RTTDCS_VMPAC 0x00000002 /* 0 Round Robin, + * 1 WRR - Weighted Round Robin + */ +#define IXGBE_RTTDCS_TDRM 0x00000010 /* Transmit Recycle Mode */ +#define IXGBE_RTTDCS_BDPM 0x00400000 /* Bypass Data Pipe - must clear! */ +#define IXGBE_RTTDCS_BPBFSM 0x00800000 /* Bypass PB Free Space - must + * clear! + */ +#define IXGBE_RTTDCS_SPEED_CHG 0x80000000 /* Link speed change */ + +/* Receive UP2TC mapping */ +#define IXGBE_RTRUP2TC_UP_SHIFT 3 +#define IXGBE_RTRUP2TC_UP_MASK 7 +/* Transmit UP2TC mapping */ +#define IXGBE_RTTUP2TC_UP_SHIFT 3 + +#define IXGBE_RTRPT4C_MCL_SHIFT 12 /* Offset to Max Credit Limit setting */ +#define IXGBE_RTRPT4C_BWG_SHIFT 9 /* Offset to BWG index */ +#define IXGBE_RTRPT4C_GSP 0x40000000 /* GSP enable bit */ +#define IXGBE_RTRPT4C_LSP 0x80000000 /* LSP enable bit */ + +#define IXGBE_RDRXCTL_MPBEN 0x00000010 /* DMA config for multiple packet + * buffers enable + */ +#define IXGBE_RDRXCTL_MCEN 0x00000040 /* DMA config for multiple cores + * (RSS) enable + */ + +/* RTRPCS Bit Masks */ +#define IXGBE_RTRPCS_RRM 0x00000002 /* Receive Recycle Mode enable */ +/* Receive Arbitration Control: 0 Round Robin, 1 DFP */ +#define IXGBE_RTRPCS_RAC 0x00000004 +#define IXGBE_RTRPCS_ARBDIS 0x00000040 /* Arbitration disable bit */ + +/* RTTDT2C Bit Masks */ +#define IXGBE_RTTDT2C_MCL_SHIFT 12 +#define IXGBE_RTTDT2C_BWG_SHIFT 9 +#define IXGBE_RTTDT2C_GSP 0x40000000 +#define IXGBE_RTTDT2C_LSP 0x80000000 + +#define IXGBE_RTTPT2C_MCL_SHIFT 12 +#define IXGBE_RTTPT2C_BWG_SHIFT 9 +#define IXGBE_RTTPT2C_GSP 0x40000000 +#define IXGBE_RTTPT2C_LSP 0x80000000 + +/* RTTPCS Bit Masks */ +#define IXGBE_RTTPCS_TPPAC 0x00000020 /* 0 Round Robin, + * 1 SP - Strict Priority + */ +#define IXGBE_RTTPCS_ARBDIS 0x00000040 /* Arbiter disable */ +#define IXGBE_RTTPCS_TPRM 0x00000100 /* Transmit Recycle Mode enable */ +#define IXGBE_RTTPCS_ARBD_SHIFT 22 +#define IXGBE_RTTPCS_ARBD_DCB 0x4 /* Arbitration delay in DCB mode */ + +#define IXGBE_TXPBTHRESH_DCB 0xA /* THRESH value for DCB mode */ + +/* SECTXMINIFG DCB */ +#define IXGBE_SECTX_DCB 0x00001F00 /* DCB TX Buffer SEC IFG */ + +/* BCN register definitions */ +#define IXGBE_RTTBCNRC_RF_INT_SHIFT 14 +#define IXGBE_RTTBCNRC_RS_ENA 0x80000000 + +#define IXGBE_RTTBCNCR_MNG_CMTGI 0x00000001 +#define IXGBE_RTTBCNCR_MGN_BCNA_MODE 0x00000002 +#define IXGBE_RTTBCNCR_RSV7_11_SHIFT 5 +#define IXGBE_RTTBCNCR_G 0x00000400 +#define IXGBE_RTTBCNCR_I 0x00000800 +#define IXGBE_RTTBCNCR_H 0x00001000 +#define IXGBE_RTTBCNCR_VER_SHIFT 14 +#define IXGBE_RTTBCNCR_CMT_ETH_SHIFT 16 + +#define IXGBE_RTTBCNACL_SMAC_L_SHIFT 16 + +#define IXGBE_RTTBCNTG_BCNA_MODE 0x80000000 + +#define IXGBE_RTTBCNRTT_TS_SHIFT 3 +#define IXGBE_RTTBCNRTT_TXQ_IDX_SHIFT 16 + +#define IXGBE_RTTBCNRD_BCN_CLEAR_ALL 0x00000002 +#define IXGBE_RTTBCNRD_DRIFT_FAC_SHIFT 2 +#define IXGBE_RTTBCNRD_DRIFT_INT_SHIFT 16 +#define IXGBE_RTTBCNRD_DRIFT_ENA 0x80000000 + + +/* DCB driver APIs */ + +/* DCB PFC */ +s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *, u8, u8 *); + +/* DCB stats */ +s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_get_tc_stats_82599(struct ixgbe_hw *, + struct ixgbe_hw_stats *, u8); +s32 ixgbe_dcb_get_pfc_stats_82599(struct ixgbe_hw *, + struct ixgbe_hw_stats *, u8); + +/* DCB config arbiters */ +s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *, u16 *, u16 *, + u8 *, u8 *); +s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *, u16 *, u16 *, + u8 *, u8 *, u8 *); +s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *, u16 *, u16 *, u8 *, + u8 *, u8 *); + +/* DCB initialization */ +s32 ixgbe_dcb_config_82599(struct ixgbe_hw *, + struct ixgbe_dcb_config *); + +s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *, int, u16 *, u16 *, u8 *, + u8 *, u8 *); +#endif /* _IXGBE_DCB_82959_H_ */ diff --git a/sys/dev/netif/ixgbe/ixgbe_mbx.c b/sys/dev/netif/ix/ixgbe_mbx.c similarity index 97% rename from sys/dev/netif/ixgbe/ixgbe_mbx.c rename to sys/dev/netif/ix/ixgbe_mbx.c index 8444ccac28..33994d4dc8 100644 --- a/sys/dev/netif/ixgbe/ixgbe_mbx.c +++ b/sys/dev/netif/ix/ixgbe_mbx.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_mbx.c,v 1.3 2012/01/30 16:42:02 jfv Exp $*/ +/*$FreeBSD$*/ #include "ixgbe_type.h" #include "ixgbe_mbx.h" @@ -77,10 +77,11 @@ s32 ixgbe_write_mbx(struct ixgbe_hw *hw, u32 *msg, u16 size, u16 mbx_id) DEBUGFUNC("ixgbe_write_mbx"); - if (size > mbx->size) + if (size > mbx->size) { ret_val = IXGBE_ERR_MBX; - - else if (mbx->ops.write) + ERROR_REPORT2(IXGBE_ERROR_ARGUMENT, + "Invalid mailbox message size %d", size); + } else if (mbx->ops.write) ret_val = mbx->ops.write(hw, msg, size, mbx_id); return ret_val; @@ -170,6 +171,10 @@ static s32 ixgbe_poll_for_msg(struct ixgbe_hw *hw, u16 mbx_id) usec_delay(mbx->usec_delay); } + if (countdown == 0) + ERROR_REPORT2(IXGBE_ERROR_POLLING, + "Polling for VF%d mailbox message timedout", mbx_id); + out: return countdown ? IXGBE_SUCCESS : IXGBE_ERR_MBX; } @@ -198,6 +203,10 @@ static s32 ixgbe_poll_for_ack(struct ixgbe_hw *hw, u16 mbx_id) usec_delay(mbx->usec_delay); } + if (countdown == 0) + ERROR_REPORT2(IXGBE_ERROR_POLLING, + "Polling for VF%d mailbox ack timedout", mbx_id); + out: return countdown ? IXGBE_SUCCESS : IXGBE_ERR_MBX; } @@ -633,6 +642,10 @@ static s32 ixgbe_obtain_mbx_lock_pf(struct ixgbe_hw *hw, u16 vf_number) p2v_mailbox = IXGBE_READ_REG(hw, IXGBE_PFMAILBOX(vf_number)); if (p2v_mailbox & IXGBE_PFMAILBOX_PFU) ret_val = IXGBE_SUCCESS; + else + ERROR_REPORT2(IXGBE_ERROR_POLLING, + "Failed to obtain mailbox lock for VF%d", vf_number); + return ret_val; } diff --git a/sys/dev/netif/ixgbe/ixgbe_mbx.h b/sys/dev/netif/ix/ixgbe_mbx.h similarity index 90% rename from sys/dev/netif/ixgbe/ixgbe_mbx.h rename to sys/dev/netif/ix/ixgbe_mbx.h index 682f1c1f65..adcba9ef59 100644 --- a/sys/dev/netif/ixgbe/ixgbe_mbx.h +++ b/sys/dev/netif/ix/ixgbe_mbx.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_mbx.h,v 1.2 2012/01/30 16:42:02 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef _IXGBE_MBX_H_ #define _IXGBE_MBX_H_ @@ -84,8 +84,20 @@ #define IXGBE_VF_SET_MAC_ADDR 0x02 /* VF requests PF to set MAC addr */ #define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */ #define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */ + +/* mailbox API, version 1.0 VF requests */ #define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */ #define IXGBE_VF_SET_MACVLAN 0x06 /* VF requests PF for unicast filter */ +#define IXGBE_VF_API_NEGOTIATE 0x08 /* negotiate API version */ + +/* mailbox API, version 1.1 VF requests */ +#define IXGBE_VF_GET_QUEUES 0x09 /* get queue configuration */ + +/* GET_QUEUES return data indices within the mailbox */ +#define IXGBE_VF_TX_QUEUES 1 /* number of Tx queues supported */ +#define IXGBE_VF_RX_QUEUES 2 /* number of Rx queues supported */ +#define IXGBE_VF_TRANS_VLAN 3 /* Indication of port vlan */ +#define IXGBE_VF_DEF_QUEUE 4 /* Default queue offset */ /* length of permanent address message returned from PF */ #define IXGBE_VF_PERMADDR_MSG_LEN 4 diff --git a/sys/dev/netif/ixgbe/ixgbe_osdep.h b/sys/dev/netif/ix/ixgbe_osdep.h similarity index 84% rename from sys/dev/netif/ixgbe/ixgbe_osdep.h rename to sys/dev/netif/ix/ixgbe_osdep.h index 283bfc8a45..763ce0211d 100644 --- a/sys/dev/netif/ixgbe/ixgbe_osdep.h +++ b/sys/dev/netif/ix/ixgbe_osdep.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_osdep.h,v 1.13 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef _IXGBE_OS_H_ #define _IXGBE_OS_H_ @@ -59,7 +59,7 @@ #define usec_delay(x) DELAY(x) #define msec_delay(x) DELAY(1000*(x)) -#define DBG 0 +#define DBG 0 #define MSGOUT(S, A, B) kprintf(S "\n", A, B) #define DEBUGFUNC(F) DEBUGOUT(F); #if DBG @@ -71,6 +71,9 @@ #define DEBUGOUT5(S,A,B,C,D,E) kprintf(S "\n",A,B,C,D,E) #define DEBUGOUT6(S,A,B,C,D,E,F) kprintf(S "\n",A,B,C,D,E,F) #define DEBUGOUT7(S,A,B,C,D,E,F,G) kprintf(S "\n",A,B,C,D,E,F,G) + #define ERROR_REPORT1(S,A) kprintf(S "\n",A) + #define ERROR_REPORT2(S,A,B) kprintf(S "\n",A,B) + #define ERROR_REPORT3(S,A,B,C) kprintf(S "\n",A,B,C) #else #define DEBUGOUT(S) #define DEBUGOUT1(S,A) @@ -80,6 +83,10 @@ #define DEBUGOUT5(S,A,B,C,D,E) #define DEBUGOUT6(S,A,B,C,D,E,F) #define DEBUGOUT7(S,A,B,C,D,E,F,G) + + #define ERROR_REPORT1(S,A) + #define ERROR_REPORT2(S,A,B) + #define ERROR_REPORT3(S,A,B,C) #endif #define FALSE 0 @@ -89,6 +96,9 @@ #define CMD_MEM_WRT_INVALIDATE 0x0010 /* BIT_4 */ #define PCI_COMMAND_REGISTER PCIR_COMMAND +/* Shared code dropped this define.. */ +#define IXGBE_VENDOR_ID 0x8086 + /* Bunch of defines for shared code bogosity */ #define UNREFERENCED_PARAMETER(_p) #define UNREFERENCED_1PARAMETER(_p) @@ -107,12 +117,11 @@ typedef uint8_t u8; typedef int8_t s8; typedef uint16_t u16; +typedef int16_t s16; typedef uint32_t u32; typedef int32_t s32; typedef uint64_t u64; -#ifndef __bool_true_false_are_defined typedef boolean_t bool; -#endif /* shared code requires this */ #define __le16 u16 @@ -125,8 +134,12 @@ typedef boolean_t bool; #define le16_to_cpu #if defined(__i386__) || defined(__x86_64__) +#define mb() __asm volatile("mfence" ::: "memory") #define wmb() __asm volatile("sfence" ::: "memory") +#define rmb() __asm volatile("lfence" ::: "memory") #else +#define mb() +#define rmb() #define wmb() #endif @@ -140,11 +153,29 @@ void prefetch(void *x) #define prefetch(x) #endif -struct ixgbe_osdep +/* + * Optimized bcopy thanks to Luigi Rizzo's investigative work. Assumes + * non-overlapping regions and 32-byte padding on both src and dst. + */ +static __inline int +ixgbe_bcopy(void *_src, void *_dst, int l) { - bus_space_tag_t mem_bus_space_tag; - bus_space_handle_t mem_bus_space_handle; - struct device *dev; + uint64_t *src = _src; + uint64_t *dst = _dst; + + for (; l > 0; l -= 32) { + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } + return (0); +} + +struct ixgbe_osdep { + bus_space_tag_t mem_bus_space_tag; + bus_space_handle_t mem_bus_space_handle; + device_t dev; }; /* These routines are needed by the shared code */ @@ -178,5 +209,4 @@ extern void ixgbe_write_pci_cfg(struct ixgbe_hw *, u32, u16); ((struct ixgbe_osdep *)(a)->back)->mem_bus_space_handle, \ (reg + ((offset) << 2)), value)) - #endif /* _IXGBE_OS_H_ */ diff --git a/sys/dev/netif/ixgbe/ixgbe_phy.c b/sys/dev/netif/ix/ixgbe_phy.c similarity index 85% rename from sys/dev/netif/ixgbe/ixgbe_phy.c rename to sys/dev/netif/ix/ixgbe_phy.c index 9277eb0c15..cb237fd4a4 100644 --- a/sys/dev/netif/ixgbe/ixgbe_phy.c +++ b/sys/dev/netif/ix/ixgbe_phy.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_phy.c,v 1.13 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #include "ixgbe_api.h" #include "ixgbe_common.h" @@ -47,6 +47,8 @@ static void ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl); static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data); static bool ixgbe_get_i2c_data(u32 *i2cctl); +static s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, + u8 *sff8472_data); /** * ixgbe_init_phy_ops_generic - Inits PHY function ptrs @@ -65,12 +67,15 @@ s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw) 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.read_reg_mdi = &ixgbe_read_phy_reg_mdi; + phy->ops.write_reg_mdi = &ixgbe_write_phy_reg_mdi; 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 = ixgbe_get_phy_firmware_version_generic; phy->ops.read_i2c_byte = &ixgbe_read_i2c_byte_generic; phy->ops.write_i2c_byte = &ixgbe_write_i2c_byte_generic; + phy->ops.read_i2c_sff8472 = &ixgbe_read_i2c_sff8472_generic; phy->ops.read_i2c_eeprom = &ixgbe_read_i2c_eeprom_generic; phy->ops.write_i2c_eeprom = &ixgbe_write_i2c_eeprom_generic; phy->ops.i2c_bus_clear = &ixgbe_i2c_bus_clear; @@ -122,8 +127,11 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) } } /* clear value if nothing found */ - if (status != IXGBE_SUCCESS) + if (status != IXGBE_SUCCESS) { hw->phy.addr = 0; + ERROR_REPORT1(IXGBE_ERROR_SOFTWARE, + "Could not identify valid PHY address"); + } } else { status = IXGBE_SUCCESS; } @@ -262,15 +270,96 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) if (ctrl & IXGBE_MDIO_PHY_XS_RESET) { status = IXGBE_ERR_RESET_FAILED; - DEBUGOUT("PHY reset polling failed to complete.\n"); + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "PHY reset polling failed to complete.\n"); } out: return status; } +/** + * ixgbe_read_phy_mdi - Reads a value from a specified PHY register without + * the SWFW lock + * @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_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, + u16 *phy_data) +{ + u32 i, data, command; + + /* 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) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address command did not complete.\n"); + return IXGBE_ERR_PHY; + } + + /* + * 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) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY read command didn't complete\n"); + return IXGBE_ERR_PHY; + } + + /* + * 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); + + return IXGBE_SUCCESS; +} + /** * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register + * using the SWFW lock - this function is needed in most cases * @hw: pointer to hardware structure * @reg_addr: 32 bit address of PHY register to read * @phy_data: Pointer to read data from PHY register @@ -278,10 +367,7 @@ out: 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; + s32 status; u16 gssr; DEBUGFUNC("ixgbe_read_phy_reg_generic"); @@ -291,85 +377,94 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, else gssr = IXGBE_GSSR_PHY0_SM; - if (hw->mac.ops.acquire_swfw_sync(hw, gssr) != IXGBE_SUCCESS) + if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) { + status = ixgbe_read_phy_reg_mdi(hw, reg_addr, device_type, + phy_data); + hw->mac.ops.release_swfw_sync(hw, gssr); + } else { 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)); + return status; +} - IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); +/** + * ixgbe_write_phy_reg_mdi - Writes a value to specified PHY register + * without SWFW lock + * @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_mdi(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u16 phy_data) +{ + u32 i, 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); + /* Put the data in the MDI single read and write data register*/ + IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data); - command = IXGBE_READ_REG(hw, IXGBE_MSCA); + /* 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)); - if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) - break; - } + IXGBE_WRITE_REG(hw, IXGBE_MSCA, command); - if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { - DEBUGOUT("PHY address command did not complete.\n"); - status = IXGBE_ERR_PHY; - } + /* + * 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); - 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; - } + 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); - } - } + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY address cmd didn't complete\n"); + return IXGBE_ERR_PHY; + } - hw->mac.ops.release_swfw_sync(hw, gssr); + /* + * 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; } - return status; + if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { + ERROR_REPORT1(IXGBE_ERROR_POLLING, "PHY write cmd didn't complete\n"); + return IXGBE_ERR_PHY; + } + + return IXGBE_SUCCESS; } /** * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register + * using SWFW lock- this function is needed in most cases * @hw: pointer to hardware structure * @reg_addr: 32 bit PHY register to write * @device_type: 5 bit device type @@ -378,9 +473,7 @@ s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, 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; + s32 status; u16 gssr; DEBUGFUNC("ixgbe_write_phy_reg_generic"); @@ -390,73 +483,12 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, else gssr = IXGBE_GSSR_PHY0_SM; - if (hw->mac.ops.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; - } - } - + if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == IXGBE_SUCCESS) { + status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, + phy_data); hw->mac.ops.release_swfw_sync(hw, gssr); + } else { + status = IXGBE_ERR_SWFW_SYNC; } return status; @@ -553,7 +585,8 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) if (time_out == max_time_out) { status = IXGBE_ERR_LINK_SETUP; - DEBUGOUT("ixgbe_setup_phy_link_generic: time out"); + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "PHY autonegotiation time out"); } return status; @@ -563,14 +596,12 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) * 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_2PARAMETER(autoneg, autoneg_wait_to_complete); + UNREFERENCED_1PARAMETER(autoneg_wait_to_complete); DEBUGFUNC("ixgbe_setup_phy_link_speed_generic"); @@ -862,6 +893,8 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) * Read control word from PHY init contents offset */ ret_val = hw->eeprom.ops.read(hw, data_offset, &eword); + if (ret_val) + goto err_eeprom; control = (eword & IXGBE_CONTROL_MASK_NL) >> IXGBE_CONTROL_SHIFT_NL; edata = eword & IXGBE_DATA_MASK_NL; @@ -874,10 +907,16 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) case IXGBE_DATA_NL: DEBUGOUT("DATA:\n"); data_offset++; - hw->eeprom.ops.read(hw, data_offset++, - &phy_offset); + ret_val = hw->eeprom.ops.read(hw, data_offset, + &phy_offset); + if (ret_val) + goto err_eeprom; + data_offset++; for (i = 0; i < edata; i++) { - hw->eeprom.ops.read(hw, data_offset, &eword); + ret_val = hw->eeprom.ops.read(hw, data_offset, + &eword); + if (ret_val) + goto err_eeprom; hw->phy.ops.write_reg(hw, phy_offset, IXGBE_TWINAX_DEV, eword); DEBUGOUT2("Wrote %4.4x to %4.4x\n", eword, @@ -909,6 +948,11 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) out: return ret_val; + +err_eeprom: + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", data_offset); + return IXGBE_ERR_PHY; } /** @@ -969,9 +1013,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) IXGBE_SFF_IDENTIFIER, &identifier); - if (status == IXGBE_ERR_SWFW_SYNC || - status == IXGBE_ERR_I2C || - status == IXGBE_ERR_SFP_NOT_PRESENT) + if (status != IXGBE_SUCCESS) goto err_read_i2c_eeprom; /* LAN ID is needed for sfp_type determination */ @@ -985,26 +1027,20 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) IXGBE_SFF_1GBE_COMP_CODES, &comp_codes_1g); - if (status == IXGBE_ERR_SWFW_SYNC || - status == IXGBE_ERR_I2C || - status == IXGBE_ERR_SFP_NOT_PRESENT) + if (status != IXGBE_SUCCESS) goto err_read_i2c_eeprom; status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES, &comp_codes_10g); - if (status == IXGBE_ERR_SWFW_SYNC || - status == IXGBE_ERR_I2C || - status == IXGBE_ERR_SFP_NOT_PRESENT) + if (status != IXGBE_SUCCESS) goto err_read_i2c_eeprom; status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_CABLE_TECHNOLOGY, &cable_tech); - if (status == IXGBE_ERR_SWFW_SYNC || - status == IXGBE_ERR_I2C || - status == IXGBE_ERR_SFP_NOT_PRESENT) + if (status != IXGBE_SUCCESS) goto err_read_i2c_eeprom; /* ID Module @@ -1102,27 +1138,21 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) IXGBE_SFF_VENDOR_OUI_BYTE0, &oui_bytes[0]); - if (status == IXGBE_ERR_SWFW_SYNC || - status == IXGBE_ERR_I2C || - status == IXGBE_ERR_SFP_NOT_PRESENT) + if (status != IXGBE_SUCCESS) goto err_read_i2c_eeprom; status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_VENDOR_OUI_BYTE1, &oui_bytes[1]); - if (status == IXGBE_ERR_SWFW_SYNC || - status == IXGBE_ERR_I2C || - status == IXGBE_ERR_SFP_NOT_PRESENT) + if (status != IXGBE_SUCCESS) goto err_read_i2c_eeprom; status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_VENDOR_OUI_BYTE2, &oui_bytes[2]); - if (status == IXGBE_ERR_SWFW_SYNC || - status == IXGBE_ERR_I2C || - status == IXGBE_ERR_SFP_NOT_PRESENT) + if (status != IXGBE_SUCCESS) goto err_read_i2c_eeprom; vendor_oui = @@ -1172,7 +1202,7 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) if (comp_codes_10g == 0 && !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || - hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { hw->phy.type = ixgbe_phy_sfp_unsupported; status = IXGBE_ERR_SFP_NOT_SUPPORTED; @@ -1187,10 +1217,10 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) ixgbe_get_device_caps(hw, &enforce_sfp); if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) && - !((hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0) || - (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1) || - (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0) || - (hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1))) { + !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core0 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_sx_core1)) { /* Make sure we're a supported PHY type */ if (hw->phy.type == ixgbe_phy_sfp_intel) { status = IXGBE_SUCCESS; @@ -1275,7 +1305,12 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, sfp_type = ixgbe_sfp_type_srlr_core1; /* Read offset to PHY init contents */ - hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset); + if (hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset)) { + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", + IXGBE_PHY_INIT_OFFSET_NL); + return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT; + } if ((!*list_offset) || (*list_offset == 0xFFFF)) return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT; @@ -1287,12 +1322,14 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, * Find the matching SFP ID in the EEPROM * and program the init sequence */ - hw->eeprom.ops.read(hw, *list_offset, &sfp_id); + if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) + goto err_phy; while (sfp_id != IXGBE_PHY_INIT_END_NL) { if (sfp_id == sfp_type) { (*list_offset)++; - hw->eeprom.ops.read(hw, *list_offset, data_offset); + if (hw->eeprom.ops.read(hw, *list_offset, data_offset)) + goto err_phy; if ((!*data_offset) || (*data_offset == 0xFFFF)) { DEBUGOUT("SFP+ module not supported\n"); return IXGBE_ERR_SFP_NOT_SUPPORTED; @@ -1302,7 +1339,7 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, } else { (*list_offset) += 2; if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) - return IXGBE_ERR_PHY; + goto err_phy; } } @@ -1312,6 +1349,11 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, } return IXGBE_SUCCESS; + +err_phy: + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "eeprom read at offset %d failed", *list_offset); + return IXGBE_ERR_PHY; } /** @@ -1332,6 +1374,22 @@ s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset, eeprom_data); } +/** + * ixgbe_read_i2c_sff8472_generic - Reads 8 bit word over I2C interface + * @hw: pointer to hardware structure + * @byte_offset: byte offset at address 0xA2 + * @eeprom_data: value read + * + * Performs byte read operation to SFP module's SFF-8472 data over I2C + **/ +static s32 ixgbe_read_i2c_sff8472_generic(struct ixgbe_hw *hw, u8 byte_offset, + u8 *sff8472_data) +{ + return hw->phy.ops.read_i2c_byte(hw, byte_offset, + IXGBE_I2C_EEPROM_DEV_ADDR2, + sff8472_data); +} + /** * ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface * @hw: pointer to hardware structure @@ -1425,9 +1483,9 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset, break; fail: + ixgbe_i2c_bus_clear(hw); hw->mac.ops.release_swfw_sync(hw, swfw_mask); msec_delay(100); - ixgbe_i2c_bus_clear(hw); retry++; if (retry < max_retry) DEBUGOUT("I2C byte read error - Retrying.\n"); @@ -1661,7 +1719,8 @@ static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw) } if (ack == 1) { - DEBUGOUT("I2C ack was not received.\n"); + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "I2C ack was not received.\n"); status = IXGBE_ERR_I2C; } @@ -1731,7 +1790,8 @@ static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data) usec_delay(IXGBE_I2C_T_LOW); } else { status = IXGBE_ERR_I2C; - DEBUGOUT1("I2C data was not set to %X\n", data); + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "I2C data was not set to %X\n", data); } return status; @@ -1815,7 +1875,9 @@ static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data) *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL); if (data != ixgbe_get_i2c_data(i2cctl)) { status = IXGBE_ERR_I2C; - DEBUGOUT1("Error - I2C data was not set to %X.\n", data); + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "Error - I2C data was not set to %X.\n", + data); } return status; @@ -1902,6 +1964,7 @@ s32 ixgbe_tn_check_overtemp(struct ixgbe_hw *hw) goto out; status = IXGBE_ERR_OVERTEMP; + ERROR_REPORT1(IXGBE_ERROR_CAUTION, "Device over temperature"); out: return status; } diff --git a/sys/dev/netif/ixgbe/ixgbe_phy.h b/sys/dev/netif/ix/ixgbe_phy.h similarity index 85% rename from sys/dev/netif/ixgbe/ixgbe_phy.h rename to sys/dev/netif/ix/ixgbe_phy.h index 5b790ef203..dd57d26bac 100644 --- a/sys/dev/netif/ixgbe/ixgbe_phy.h +++ b/sys/dev/netif/ix/ixgbe_phy.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,13 +30,15 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_phy.h,v 1.12 2012/01/30 16:42:02 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef _IXGBE_PHY_H_ #define _IXGBE_PHY_H_ #include "ixgbe_type.h" -#define IXGBE_I2C_EEPROM_DEV_ADDR 0xA0 +#define IXGBE_I2C_EEPROM_DEV_ADDR 0xA0 +#define IXGBE_I2C_EEPROM_DEV_ADDR2 0xA2 +#define IXGBE_I2C_EEPROM_BANK_LEN 0xFF /* EEPROM byte offsets */ #define IXGBE_SFF_IDENTIFIER 0x0 @@ -48,6 +50,10 @@ #define IXGBE_SFF_10GBE_COMP_CODES 0x3 #define IXGBE_SFF_CABLE_TECHNOLOGY 0x8 #define IXGBE_SFF_CABLE_SPEC_COMP 0x3C +#define IXGBE_SFF_SFF_8472_SWAP 0x5C +#define IXGBE_SFF_SFF_8472_COMP 0x5E +#define IXGBE_SFF_SFF_8472_OSCB 0x6E +#define IXGBE_SFF_SFF_8472_ESCB 0x76 /* Bitmasks */ #define IXGBE_SFF_DA_PASSIVE_CABLE 0x4 @@ -58,6 +64,9 @@ #define IXGBE_SFF_1GBASET_CAPABLE 0x8 #define IXGBE_SFF_10GBASESR_CAPABLE 0x10 #define IXGBE_SFF_10GBASELR_CAPABLE 0x20 +#define IXGBE_SFF_SOFT_RS_SELECT_MASK 0x8 +#define IXGBE_SFF_SOFT_RS_SELECT_10G 0x8 +#define IXGBE_SFF_SOFT_RS_SELECT_1G 0x0 #define IXGBE_I2C_EEPROM_READ_MASK 0x100 #define IXGBE_I2C_EEPROM_STATUS_MASK 0x3 #define IXGBE_I2C_EEPROM_STATUS_NO_OPERATION 0x0 @@ -95,12 +104,24 @@ #define IXGBE_TN_LASI_STATUS_REG 0x9005 #define IXGBE_TN_LASI_STATUS_TEMP_ALARM 0x0008 +/* SFP+ SFF-8472 Compliance */ +#define IXGBE_SFF_SFF_8472_UNSUP 0x00 +#define IXGBE_SFF_SFF_8472_REV_9_3 0x01 +#define IXGBE_SFF_SFF_8472_REV_9_5 0x02 +#define IXGBE_SFF_SFF_8472_REV_10_2 0x03 +#define IXGBE_SFF_SFF_8472_REV_10_4 0x04 +#define IXGBE_SFF_SFF_8472_REV_11_0 0x05 + 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_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, + u16 *phy_data); +s32 ixgbe_write_phy_reg_mdi(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, + u16 phy_data); 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, @@ -108,7 +129,6 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, 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_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, diff --git a/sys/dev/netif/ixgbe/ixgbe_type.h b/sys/dev/netif/ix/ixgbe_type.h similarity index 95% rename from sys/dev/netif/ixgbe/ixgbe_type.h rename to sys/dev/netif/ix/ixgbe_type.h index c6892c405a..764abbf11b 100644 --- a/sys/dev/netif/ixgbe/ixgbe_type.h +++ b/sys/dev/netif/ix/ixgbe_type.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,11 +30,49 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_type.h,v 1.14 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef _IXGBE_TYPE_H_ #define _IXGBE_TYPE_H_ +/* + * The following is a brief description of the error categories used by the + * ERROR_REPORT* macros. + * + * - IXGBE_ERROR_INVALID_STATE + * This category is for errors which represent a serious failure state that is + * unexpected, and could be potentially harmful to device operation. It should + * not be used for errors relating to issues that can be worked around or + * ignored. + * + * - IXGBE_ERROR_POLLING + * This category is for errors related to polling/timeout issues and should be + * used in any case where the timeout occured, or a failure to obtain a lock, or + * failure to receive data within the time limit. + * + * - IXGBE_ERROR_CAUTION + * This category should be used for reporting issues that may be the cause of + * other errors, such as temperature warnings. It should indicate an event which + * could be serious, but hasn't necessarily caused problems yet. + * + * - IXGBE_ERROR_SOFTWARE + * This category is intended for errors due to software state preventing + * something. The category is not intended for errors due to bad arguments, or + * due to unsupported features. It should be used when a state occurs which + * prevents action but is not a serious issue. + * + * - IXGBE_ERROR_ARGUMENT + * This category is for when a bad or invalid argument is passed. It should be + * used whenever a function is called and error checking has detected the + * argument is wrong or incorrect. + * + * - IXGBE_ERROR_UNSUPPORTED + * This category is for errors which are due to unsupported circumstances or + * configuration issues. It should not be used when the issue is due to an + * invalid argument, but for when something has occurred that is unsupported + * (Ex: Flow control autonegotiation or an unsupported SFP+ module.) + */ + #include "ixgbe_osdep.h" @@ -62,18 +100,27 @@ #define IXGBE_DEV_ID_82599_CX4 0x10F9 #define IXGBE_DEV_ID_82599_SFP 0x10FB #define IXGBE_SUBDEV_ID_82599_SFP 0x11A9 +#define IXGBE_SUBDEV_ID_82599_RNDC 0x1F72 #define IXGBE_SUBDEV_ID_82599_560FLR 0x17D0 +#define IXGBE_SUBDEV_ID_82599_ECNA_DP 0x0470 +#define IXGBE_SUBDEV_ID_82599_SP_560FLR 0x211B +#define IXGBE_SUBDEV_ID_82599_LOM_SFP 0x8976 #define IXGBE_DEV_ID_82599_BACKPLANE_FCOE 0x152A #define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529 #define IXGBE_DEV_ID_82599_SFP_EM 0x1507 #define IXGBE_DEV_ID_82599_SFP_SF2 0x154D +#define IXGBE_DEV_ID_82599_SFP_SF_QP 0x154A #define IXGBE_DEV_ID_82599EN_SFP 0x1557 +#define IXGBE_SUBDEV_ID_82599EN_SFP_OCP1 0x0001 #define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC #define IXGBE_DEV_ID_82599_T3_LOM 0x151C #define IXGBE_DEV_ID_82599_VF 0x10ED -#define IXGBE_DEV_ID_X540_VF 0x1515 +#define IXGBE_DEV_ID_82599_VF_HV 0x152E +#define IXGBE_DEV_ID_82599_BYPASS 0x155D #define IXGBE_DEV_ID_X540T 0x1528 -#define IXGBE_DEV_ID_X540T1 0x1560 +#define IXGBE_DEV_ID_X540_VF 0x1515 +#define IXGBE_DEV_ID_X540_VF_HV 0x1530 +#define IXGBE_DEV_ID_X540_BYPASS 0x155C /* General Registers */ #define IXGBE_CTRL 0x00000 @@ -209,12 +256,12 @@ (((_i) < 64) ? (0x0100C + ((_i) * 0x40)) : \ (0x0D00C + (((_i) - 64) * 0x40)))) #define IXGBE_RDRXCTL 0x02F00 -#define IXGBE_RDRXCTL_RSC_PUSH 0x80 /* 8 of these 0x03C00 - 0x03C1C */ #define IXGBE_RXPBSIZE(_i) (0x03C00 + ((_i) * 4)) #define IXGBE_RXCTRL 0x03000 #define IXGBE_DROPEN 0x03D04 #define IXGBE_RXPBSIZE_SHIFT 10 +#define IXGBE_RXPBSIZE_MASK 0x000FFC00 /* Receive Registers */ #define IXGBE_RXCSUM 0x05000 @@ -280,6 +327,7 @@ #define IXGBE_RETA(_i) (0x05C00 + ((_i) * 4)) /* 32 of these (0-31) */ #define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* 10 of these (0-9) */ + /* Flow Director registers */ #define IXGBE_FDIRCTRL 0x0EE00 #define IXGBE_FDIRHKEY 0x0EE68 @@ -360,11 +408,16 @@ #define IXGBE_WUPL 0x05900 #define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */ + #define IXGBE_FHFT(_n) (0x09000 + (_n * 0x100)) /* Flex host filter table */ /* Ext Flexible Host Filter Table */ #define IXGBE_FHFT_EXT(_n) (0x09800 + (_n * 0x100)) +/* Four Flexible Filters are supported */ #define IXGBE_FLEXIBLE_FILTER_COUNT_MAX 4 + +/* Six Flexible Filters are supported */ +#define IXGBE_FLEXIBLE_FILTER_COUNT_MAX_6 6 #define IXGBE_EXT_FLEXIBLE_FILTER_COUNT_MAX 2 /* Each Flexible Filter is at most 128 (0x80) bytes in length */ @@ -396,10 +449,11 @@ #define IXGBE_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ #define IXGBE_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */ #define IXGBE_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */ -#define IXGBE_WUFC_FLX_FILTERS 0x000F0000 /* Mask for 4 flex filters */ +#define IXGBE_WUFC_FLX_FILTERS 0x000F0000 /* Mask for 4 flex filters */ /* Mask for Ext. flex filters */ #define IXGBE_WUFC_EXT_FLX_FILTERS 0x00300000 -#define IXGBE_WUFC_ALL_FILTERS 0x003F00FF /* Mask for all wakeup filters */ +#define IXGBE_WUFC_ALL_FILTERS 0x000F00FF /* Mask all 4 flex filters */ +#define IXGBE_WUFC_ALL_FILTERS_6 0x003F00FF /* Mask all 6 flex filters */ #define IXGBE_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ /* Wake Up Status */ @@ -420,7 +474,6 @@ #define IXGBE_WUS_FLX5 IXGBE_WUFC_FLX5 #define IXGBE_WUS_FLX_FILTERS IXGBE_WUFC_FLX_FILTERS -/* Wake Up Packet Length */ #define IXGBE_WUPL_LENGTH_MASK 0xFFFF /* DCB registers */ @@ -437,6 +490,7 @@ #define IXGBE_TDPT2TCSR(_i) (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */ + /* Security Control Registers */ #define IXGBE_SECTXCTRL 0x08800 #define IXGBE_SECTXSTAT 0x08804 @@ -574,13 +628,12 @@ #define IXGBE_RTTBCNRTT 0x05150 #define IXGBE_RTTBCNRD 0x0498C + /* FCoE DMA Context Registers */ #define IXGBE_FCPTRL 0x02410 /* FC User Desc. PTR Low */ #define IXGBE_FCPTRH 0x02414 /* FC USer Desc. PTR High */ #define IXGBE_FCBUFF 0x02418 /* FC Buffer Control */ #define IXGBE_FCDMARW 0x02420 /* FC Receive DMA RW */ -#define IXGBE_FCINVST0 0x03FC0 /* FC Invalid DMA Context Status Reg 0*/ -#define IXGBE_FCINVST(_i) (IXGBE_FCINVST0 + ((_i) * 4)) #define IXGBE_FCBUFF_VALID (1 << 0) /* DMA Context Valid */ #define IXGBE_FCBUFF_BUFFSIZE (3 << 3) /* User Buffer Size */ #define IXGBE_FCBUFF_WRCONTX (1 << 7) /* 0: Initiator, 1: Target */ @@ -754,11 +807,14 @@ #define IXGBE_BMCIP_IPADDR_VALID 0x00000002 /* Management Bit Fields and Masks */ +#define IXGBE_MANC_RCV_TCO_EN 0x00020000 /* Rcv TCO packet enable */ #define IXGBE_MANC_EN_BMC2OS 0x10000000 /* Ena BMC2OS and OS2BMC traffic */ #define IXGBE_MANC_EN_BMC2OS_SHIFT 28 /* Firmware Semaphore Register */ #define IXGBE_FWSM_MODE_MASK 0xE +#define IXGBE_FWSM_TS_ENABLED 0x1 +#define IXGBE_FWSM_FW_MODE_PT 0x4 /* ARC Subsystem registers */ #define IXGBE_HICR 0x15F00 @@ -874,8 +930,6 @@ #define IXGBE_RDPROBE 0x02F20 #define IXGBE_RDMAM 0x02F30 #define IXGBE_RDMAD 0x02F34 -#define IXGBE_TDSTATCTL 0x07C20 -#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */ #define IXGBE_TDHMPN 0x07F08 #define IXGBE_TDHMPN2 0x082FC #define IXGBE_TXDESCIC 0x082CC @@ -1014,6 +1068,7 @@ #define IXGBE_RSCCTL_MAXDESC_4 0x04 #define IXGBE_RSCCTL_MAXDESC_8 0x08 #define IXGBE_RSCCTL_MAXDESC_16 0x0C +#define IXGBE_RSCCTL_TS_DIS 0x02 /* RSCDBU Bit Masks */ #define IXGBE_RSCDBU_RSCSMALDIS_MASK 0x0000007F @@ -1023,10 +1078,12 @@ #define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000 /* Rx Desc Min THLD Size */ #define IXGBE_RDRXCTL_CRCSTRIP 0x00000002 /* CRC Strip */ #define IXGBE_RDRXCTL_MVMEN 0x00000020 +#define IXGBE_RDRXCTL_RSC_PUSH_DIS 0x00000020 #define IXGBE_RDRXCTL_DMAIDONE 0x00000008 /* DMA init cycle done */ +#define IXGBE_RDRXCTL_RSC_PUSH 0x00000080 #define IXGBE_RDRXCTL_AGGDIS 0x00010000 /* Aggregation disable */ #define IXGBE_RDRXCTL_RSCFRSTSIZE 0x003E0000 /* RSC First packet size */ -#define IXGBE_RDRXCTL_RSCLLIDIS 0x00800000 /* Disabl RSC compl on LLI */ +#define IXGBE_RDRXCTL_RSCLLIDIS 0x00800000 /* Disable RSC compl on LLI*/ #define IXGBE_RDRXCTL_RSCACKC 0x02000000 /* must set 1 when RSC ena */ #define IXGBE_RDRXCTL_FCOE_WRFIX 0x04000000 /* must set 1 when RSC ena */ @@ -1052,6 +1109,7 @@ #define IXGBE_CTRL_RST_MASK (IXGBE_CTRL_LNK_RST | IXGBE_CTRL_RST) /* FACTPS */ +#define IXGBE_FACTPS_MNGCG 0x20000000 /* Manageblility Clock Gated */ #define IXGBE_FACTPS_LFS 0x40000000 /* LAN Function Select */ /* MHADD Bit Masks */ @@ -1590,6 +1648,7 @@ enum { #define IXGBE_ESDP_SDP7 0x00000080 /* SDP7 Data Value */ #define IXGBE_ESDP_SDP0_DIR 0x00000100 /* SDP0 IO direction */ #define IXGBE_ESDP_SDP1_DIR 0x00000200 /* SDP1 IO direction */ +#define IXGBE_ESDP_SDP2_DIR 0x00000400 /* SDP1 IO direction */ #define IXGBE_ESDP_SDP3_DIR 0x00000800 /* SDP3 IO direction */ #define IXGBE_ESDP_SDP4_DIR 0x00001000 /* SDP4 IO direction */ #define IXGBE_ESDP_SDP5_DIR 0x00002000 /* SDP5 IO direction */ @@ -1668,6 +1727,8 @@ enum { #define IXGBE_AUTOC2_10G_KR (0x0 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT) #define IXGBE_AUTOC2_10G_XFI (0x1 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT) #define IXGBE_AUTOC2_10G_SFI (0x2 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT) +#define IXGBE_AUTOC2_LINK_DISABLE_ON_D3_MASK 0x50000000 +#define IXGBE_AUTOC2_LINK_DISABLE_MASK 0x70000000 #define IXGBE_MACC_FLU 0x00000001 #define IXGBE_MACC_FSV_10G 0x00030000 @@ -1838,8 +1899,10 @@ enum { #define IXGBE_ETH_LENGTH_OF_ADDRESS 6 #define IXGBE_EEPROM_PAGE_SIZE_MAX 128 -#define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* words rd in burst */ +#define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 256 /* words rd in burst */ #define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* words wr in burst */ +#define IXGBE_EEPROM_CTRL_2 1 /* EEPROM CTRL word 2 */ +#define IXGBE_EEPROM_CCD_BIT 2 #ifndef IXGBE_EEPROM_GRANT_ATTEMPTS #define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM attempts to gain grant */ @@ -1880,6 +1943,18 @@ enum { #define IXGBE_ALT_SAN_MAC_ADDR_CAPS_SANMAC 0x0 /* Alt SAN MAC exists */ #define IXGBE_ALT_SAN_MAC_ADDR_CAPS_ALTWWN 0x1 /* Alt WWN base exists */ +/* FW header offset */ +#define IXGBE_X540_FW_PASSTHROUGH_PATCH_CONFIG_PTR 0x4 +#define IXGBE_X540_FW_MODULE_MASK 0x7FFF +/* 4KB multiplier */ +#define IXGBE_X540_FW_MODULE_LENGTH 0x1000 +/* version word 2 (month & day) */ +#define IXGBE_X540_FW_PATCH_VERSION_2 0x5 +/* version word 3 (silicon compatibility & year) */ +#define IXGBE_X540_FW_PATCH_VERSION_3 0x6 +/* version word 4 (major & minor numbers) */ +#define IXGBE_X540_FW_PATCH_VERSION_4 0x7 + #define IXGBE_DEVICE_CAPS_WOL_PORT0_1 0x4 /* WoL supported on ports 0 & 1 */ #define IXGBE_DEVICE_CAPS_WOL_PORT0 0x8 /* WoL supported on port 0 */ #define IXGBE_DEVICE_CAPS_WOL_MASK 0xC /* Mask for WoL capabilities */ @@ -1902,6 +1977,17 @@ enum { #define IXGBE_PCI_HEADER_TYPE_MULTIFUNC 0x80 #define IXGBE_PCI_DEVICE_CONTROL2_16ms 0x0005 +#define IXGBE_PCIDEVCTRL2_TIMEO_MASK 0xf +#define IXGBE_PCIDEVCTRL2_16_32ms_def 0x0 +#define IXGBE_PCIDEVCTRL2_50_100us 0x1 +#define IXGBE_PCIDEVCTRL2_1_2ms 0x2 +#define IXGBE_PCIDEVCTRL2_16_32ms 0x5 +#define IXGBE_PCIDEVCTRL2_65_130ms 0x6 +#define IXGBE_PCIDEVCTRL2_260_520ms 0x9 +#define IXGBE_PCIDEVCTRL2_1_2s 0xa +#define IXGBE_PCIDEVCTRL2_4_8s 0xd +#define IXGBE_PCIDEVCTRL2_17_34s 0xe + /* Number of 100 microseconds we wait for PCI Express master disable */ #define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800 @@ -1924,7 +2010,7 @@ enum { #define IXGBE_RFCTL_ISCSI_DIS 0x00000001 #define IXGBE_RFCTL_ISCSI_DWC_MASK 0x0000003E #define IXGBE_RFCTL_ISCSI_DWC_SHIFT 1 -#define IXGBE_RFCTL_RSC_DIS 0x00000010 +#define IXGBE_RFCTL_RSC_DIS 0x00000020 #define IXGBE_RFCTL_NFSW_DIS 0x00000040 #define IXGBE_RFCTL_NFSR_DIS 0x00000080 #define IXGBE_RFCTL_NFS_VER_MASK 0x00000300 @@ -2331,6 +2417,14 @@ enum ixgbe_fdir_pballoc_type { #define IXGBE_FDIR_DROP_QUEUE 127 #define IXGBE_STATUS_OVERHEATING_BIT 20 /* STATUS overtemp bit num */ +/* iTS sensor related defines*/ +#define IXGBE_TEMP_STATUS_ADDR_X540 0xC830 +#define IXGBE_TEMP_VALUE_ADDR_X540 0xC820 +#define IXGBE_TEMP_PROV_2_ADDR_X540 0xC421 +#define IXGBE_TEMP_PROV_4_ADDR_X540 0xC423 +#define IXGBE_TEMP_STATUS_PAGE_X540 0x1E +#define IXGBE_TEMP_HIGH_FAILURE_BIT_X540 0xE +#define IXGBE_TEMP_HIGH_WARNING_BIT_X540 0xC /* Manageablility Host Interface defines */ #define IXGBE_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */ @@ -2524,7 +2618,6 @@ typedef u32 ixgbe_link_speed; IXGBE_LINK_SPEED_1GB_FULL | \ IXGBE_LINK_SPEED_10GB_FULL) - /* Physical layer type */ typedef u32 ixgbe_physical_layer; #define IXGBE_PHYSICAL_LAYER_UNKNOWN 0 @@ -2757,6 +2850,7 @@ enum ixgbe_sfp_type { enum ixgbe_media_type { ixgbe_media_type_unknown = 0, ixgbe_media_type_fiber, + ixgbe_media_type_fiber_fixed, ixgbe_media_type_copper, ixgbe_media_type_backplane, ixgbe_media_type_cx4, @@ -2975,7 +3069,7 @@ struct ixgbe_mac_operations { void (*disable_tx_laser)(struct ixgbe_hw *); void (*enable_tx_laser)(struct ixgbe_hw *); void (*flap_tx_laser)(struct ixgbe_hw *); - s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool); + s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool); s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); @@ -3016,6 +3110,10 @@ struct ixgbe_mac_operations { /* Manageability interface */ s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8); + s32 (*dmac_config)(struct ixgbe_hw *hw); + s32 (*dmac_update_tcs)(struct ixgbe_hw *hw); + s32 (*dmac_config_tcs)(struct ixgbe_hw *hw); + void (*get_rtrup2tc)(struct ixgbe_hw *hw, u8 *map); }; struct ixgbe_phy_operations { @@ -3025,13 +3123,15 @@ struct ixgbe_phy_operations { s32 (*reset)(struct ixgbe_hw *); s32 (*read_reg)(struct ixgbe_hw *, u32, u32, u16 *); s32 (*write_reg)(struct ixgbe_hw *, u32, u32, u16); + s32 (*read_reg_mdi)(struct ixgbe_hw *, u32, u32, u16 *); + s32 (*write_reg_mdi)(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 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool); s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); s32 (*get_firmware_version)(struct ixgbe_hw *, u16 *); s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *); s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8); + s32 (*read_i2c_sff8472)(struct ixgbe_hw *, u8 , u8 *); s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *); s32 (*write_i2c_eeprom)(struct ixgbe_hw *, u8, u8); void (*i2c_bus_clear)(struct ixgbe_hw *); @@ -3069,7 +3169,9 @@ struct ixgbe_mac_info { u32 max_tx_queues; u32 max_rx_queues; u32 orig_autoc; + u32 cached_autoc; u8 san_mac_rar_index; + bool get_link_status; u32 orig_autoc2; u16 max_msix_vectors; bool arc_subsystem_valid; @@ -3142,8 +3244,11 @@ struct ixgbe_hw { u16 subsystem_vendor_id; u8 revision_id; bool adapter_stopped; + int api_version; bool force_full_reset; bool allow_unsupported_sfp; + bool mng_fw_enabled; + bool wol_enabled; }; #define ixgbe_call_func(hw, func, params, error) \ @@ -3185,8 +3290,9 @@ struct ixgbe_hw { #define IXGBE_ERR_INVALID_ARGUMENT -32 #define IXGBE_ERR_HOST_INTERFACE_COMMAND -33 #define IXGBE_ERR_OUT_OF_MEM -34 +#define IXGBE_ERR_FEATURE_NOT_SUPPORTED -36 +#define IXGBE_ERR_EEPROM_PROTECTED_REGION -37 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF - #endif /* _IXGBE_TYPE_H_ */ diff --git a/sys/dev/netif/ixgbe/ixgbe_vf.c b/sys/dev/netif/ix/ixgbe_vf.c similarity index 79% rename from sys/dev/netif/ixgbe/ixgbe_vf.c rename to sys/dev/netif/ix/ixgbe_vf.c index 2b5ba215fd..f8dffbb591 100644 --- a/sys/dev/netif/ixgbe/ixgbe_vf.c +++ b/sys/dev/netif/ix/ixgbe_vf.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_vf.c,v 1.3 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #include "ixgbe_api.h" @@ -134,7 +134,7 @@ s32 ixgbe_reset_hw_vf(struct ixgbe_hw *hw) struct ixgbe_mbx_info *mbx = &hw->mbx; u32 timeout = IXGBE_VF_INIT_TIMEOUT; s32 ret_val = IXGBE_ERR_INVALID_MAC_ADDR; - u32 ctrl, msgbuf[IXGBE_VF_PERMADDR_MSG_LEN]; + u32 msgbuf[IXGBE_VF_PERMADDR_MSG_LEN]; u8 *addr = (u8 *)(&msgbuf[1]); DEBUGFUNC("ixgbevf_reset_hw_vf"); @@ -142,10 +142,10 @@ s32 ixgbe_reset_hw_vf(struct ixgbe_hw *hw) /* Call adapter stop to disable tx/rx and clear interrupts */ hw->mac.ops.stop_adapter(hw); + DEBUGOUT("Issuing a function level reset to MAC\n"); - ctrl = IXGBE_VFREAD_REG(hw, IXGBE_VFCTRL) | IXGBE_CTRL_RST; - IXGBE_VFWRITE_REG(hw, IXGBE_VFCTRL, ctrl); + IXGBE_VFWRITE_REG(hw, IXGBE_VFCTRL, IXGBE_CTRL_RST); IXGBE_WRITE_FLUSH(hw); msec_delay(50); @@ -156,34 +156,33 @@ s32 ixgbe_reset_hw_vf(struct ixgbe_hw *hw) usec_delay(5); } - if (timeout) { - /* mailbox timeout can now become active */ - mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT; - - msgbuf[0] = IXGBE_VF_RESET; - mbx->ops.write_posted(hw, msgbuf, 1, 0); - - msec_delay(10); - - /* - * set our "perm_addr" based on info provided by PF - * also set up the mc_filter_type which is piggy backed - * on the mac address in word 3 - */ - ret_val = mbx->ops.read_posted(hw, msgbuf, - IXGBE_VF_PERMADDR_MSG_LEN, 0); - if (!ret_val) { - if (msgbuf[0] == (IXGBE_VF_RESET | - IXGBE_VT_MSGTYPE_ACK)) { - memcpy(hw->mac.perm_addr, addr, - IXGBE_ETH_LENGTH_OF_ADDRESS); - hw->mac.mc_filter_type = - msgbuf[IXGBE_VF_MC_TYPE_WORD]; - } else { - ret_val = IXGBE_ERR_INVALID_MAC_ADDR; - } - } - } + if (!timeout) + return IXGBE_ERR_RESET_FAILED; + + /* mailbox timeout can now become active */ + mbx->timeout = IXGBE_VF_MBX_INIT_TIMEOUT; + + msgbuf[0] = IXGBE_VF_RESET; + mbx->ops.write_posted(hw, msgbuf, 1, 0); + + msec_delay(10); + + /* + * set our "perm_addr" based on info provided by PF + * also set up the mc_filter_type which is piggy backed + * on the mac address in word 3 + */ + ret_val = mbx->ops.read_posted(hw, msgbuf, + IXGBE_VF_PERMADDR_MSG_LEN, 0); + if (ret_val) + return ret_val; + + if (msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_ACK) && + msgbuf[0] != (IXGBE_VF_RESET | IXGBE_VT_MSGTYPE_NACK)) + return IXGBE_ERR_INVALID_MAC_ADDR; + + memcpy(hw->mac.perm_addr, addr, IXGBE_ETH_LENGTH_OF_ADDRESS); + hw->mac.mc_filter_type = msgbuf[IXGBE_VF_MC_TYPE_WORD]; return ret_val; } @@ -272,6 +271,17 @@ static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr) return vector; } +static void ixgbevf_write_msg_read_ack(struct ixgbe_hw *hw, + u32 *msg, u16 size) +{ + struct ixgbe_mbx_info *mbx = &hw->mbx; + u32 retmsg[IXGBE_VFMAILBOX_SIZE]; + s32 retval = mbx->ops.write_posted(hw, msg, size, 0); + + if (!retval) + mbx->ops.read_posted(hw, retmsg, size, 0); +} + /** * ixgbe_set_rar_vf - set device MAC address * @hw: pointer to hardware structure @@ -463,11 +473,10 @@ s32 ixgbevf_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr) * * Set the link speed in the AUTOC register and restarts link. **/ -s32 ixgbe_setup_mac_link_vf(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, +s32 ixgbe_setup_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg_wait_to_complete) { - UNREFERENCED_4PARAMETER(hw, speed, autoneg, autoneg_wait_to_complete); + UNREFERENCED_3PARAMETER(hw, speed, autoneg_wait_to_complete); return IXGBE_SUCCESS; } @@ -483,23 +492,26 @@ s32 ixgbe_setup_mac_link_vf(struct ixgbe_hw *hw, s32 ixgbe_check_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up, bool autoneg_wait_to_complete) { + struct ixgbe_mbx_info *mbx = &hw->mbx; + struct ixgbe_mac_info *mac = &hw->mac; + s32 ret_val = IXGBE_SUCCESS; u32 links_reg; + u32 in_msg = 0; UNREFERENCED_1PARAMETER(autoneg_wait_to_complete); - if (!(hw->mbx.ops.check_for_rst(hw, 0))) { - *link_up = FALSE; - *speed = 0; - return -1; - } + /* If we were hit with a reset drop the link */ + if (!mbx->ops.check_for_rst(hw, 0) || !mbx->timeout) + mac->get_link_status = TRUE; - links_reg = IXGBE_VFREAD_REG(hw, IXGBE_VFLINKS); + if (!mac->get_link_status) + goto out; - if (links_reg & IXGBE_LINKS_UP) - *link_up = TRUE; - else - *link_up = FALSE; + /* if link status is down no point in checking to see if pf is up */ + links_reg = IXGBE_READ_REG(hw, IXGBE_VFLINKS); + if (!(links_reg & IXGBE_LINKS_UP)) + goto out; - switch (links_reg & IXGBE_LINKS_SPEED_10G_82599) { + switch (links_reg & IXGBE_LINKS_SPEED_82599) { case IXGBE_LINKS_SPEED_10G_82599: *speed = IXGBE_LINK_SPEED_10GB_FULL; break; @@ -511,6 +523,87 @@ s32 ixgbe_check_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed *speed, break; } + /* if the read failed it could just be a mailbox collision, best wait + * until we are called again and don't report an error + */ + if (mbx->ops.read(hw, &in_msg, 1, 0)) + goto out; + + if (!(in_msg & IXGBE_VT_MSGTYPE_CTS)) { + /* msg is not CTS and is NACK we must have lost CTS status */ + if (in_msg & IXGBE_VT_MSGTYPE_NACK) + ret_val = -1; + goto out; + } + + /* the pf is talking, if we timed out in the past we reinit */ + if (!mbx->timeout) { + ret_val = -1; + goto out; + } + + /* if we passed all the tests above then the link is up and we no + * longer need to check for link + */ + mac->get_link_status = FALSE; + +out: + *link_up = !mac->get_link_status; + return ret_val; +} + +/** + * ixgbevf_rlpml_set_vf - Set the maximum receive packet length + * @hw: pointer to the HW structure + * @max_size: value to assign to max frame size + **/ +void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size) +{ + u32 msgbuf[2]; + + msgbuf[0] = IXGBE_VF_SET_LPE; + msgbuf[1] = max_size; + ixgbevf_write_msg_read_ack(hw, msgbuf, 2); +} + +/** + * ixgbevf_negotiate_api_version - Negotiate supported API version + * @hw: pointer to the HW structure + * @api: integer containing requested API version + **/ +int ixgbevf_negotiate_api_version(struct ixgbe_hw *hw, int api) +{ + int err; + u32 msg[3]; + + /* Negotiate the mailbox API version */ + msg[0] = IXGBE_VF_API_NEGOTIATE; + msg[1] = api; + msg[2] = 0; + err = hw->mbx.ops.write_posted(hw, msg, 3, 0); + + if (!err) + err = hw->mbx.ops.read_posted(hw, msg, 3, 0); + + if (!err) { + msg[0] &= ~IXGBE_VT_MSGTYPE_CTS; + + /* Store value and return 0 on success */ + if (msg[0] == (IXGBE_VF_API_NEGOTIATE | IXGBE_VT_MSGTYPE_ACK)) { + hw->api_version = api; + return 0; + } + + err = IXGBE_ERR_INVALID_ARGUMENT; + } + + return err; +} + +int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs, + unsigned int *default_tc) +{ + UNREFERENCED_3PARAMETER(hw, num_tcs, default_tc); return IXGBE_SUCCESS; } diff --git a/sys/dev/netif/ixgbe/ixgbe_vf.h b/sys/dev/netif/ix/ixgbe_vf.h similarity index 92% rename from sys/dev/netif/ixgbe/ixgbe_vf.h rename to sys/dev/netif/ix/ixgbe_vf.h index 41f9029989..8500768880 100644 --- a/sys/dev/netif/ixgbe/ixgbe_vf.h +++ b/sys/dev/netif/ix/ixgbe_vf.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_vf.h,v 1.2 2012/01/30 16:42:02 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef __IXGBE_VF_H__ #define __IXGBE_VF_H__ @@ -39,6 +39,9 @@ #define IXGBE_VF_MAX_TX_QUEUES 8 #define IXGBE_VF_MAX_RX_QUEUES 8 +/* DCB define */ +#define IXGBE_VF_MAX_TRAFFIC_CLASS 8 + #define IXGBE_VFCTRL 0x00000 #define IXGBE_VFSTATUS 0x00008 #define IXGBE_VFLINKS 0x00010 @@ -117,7 +120,7 @@ u32 ixgbe_get_num_of_tx_queues_vf(struct ixgbe_hw *hw); u32 ixgbe_get_num_of_rx_queues_vf(struct ixgbe_hw *hw); s32 ixgbe_get_mac_addr_vf(struct ixgbe_hw *hw, u8 *mac_addr); s32 ixgbe_setup_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool autoneg_wait_to_complete); + bool autoneg_wait_to_complete); s32 ixgbe_check_mac_link_vf(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *link_up, bool autoneg_wait_to_complete); s32 ixgbe_set_rar_vf(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, @@ -127,5 +130,9 @@ s32 ixgbe_update_mc_addr_list_vf(struct ixgbe_hw *hw, u8 *mc_addr_list, u32 mc_addr_count, ixgbe_mc_addr_itr, bool clear); s32 ixgbe_set_vfta_vf(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on); +void ixgbevf_rlpml_set_vf(struct ixgbe_hw *hw, u16 max_size); +int ixgbevf_negotiate_api_version(struct ixgbe_hw *hw, int api); +int ixgbevf_get_queues(struct ixgbe_hw *hw, unsigned int *num_tcs, + unsigned int *default_tc); #endif /* __IXGBE_VF_H__ */ diff --git a/sys/dev/netif/ixgbe/ixgbe_x540.c b/sys/dev/netif/ix/ixgbe_x540.c similarity index 92% rename from sys/dev/netif/ixgbe/ixgbe_x540.c rename to sys/dev/netif/ix/ixgbe_x540.c index f662c76cf9..700ee9b6d9 100644 --- a/sys/dev/netif/ixgbe/ixgbe_x540.c +++ b/sys/dev/netif/ix/ixgbe_x540.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_x540.c,v 1.2 2012/07/05 20:51:44 jfv Exp $*/ +/*$FreeBSD$*/ #include "ixgbe_x540.h" #include "ixgbe_type.h" @@ -38,7 +38,6 @@ #include "ixgbe_common.h" #include "ixgbe_phy.h" -static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw); static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw); static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw); static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw); @@ -116,6 +115,7 @@ s32 ixgbe_init_ops_X540(struct ixgbe_hw *hw) mac->ops.setup_rxpba = &ixgbe_set_rxpba_generic; mac->ops.check_link = &ixgbe_check_mac_link_generic; + mac->mcft_size = 128; mac->vft_size = 128; mac->num_rar_entries = 128; @@ -141,6 +141,8 @@ s32 ixgbe_init_ops_X540(struct ixgbe_hw *hw) /* Manageability interface */ mac->ops.set_fw_drv_ver = &ixgbe_set_fw_drv_ver_generic; + mac->ops.get_rtrup2tc = &ixgbe_dcb_get_rtrup2tc_generic; + return ret_val; } @@ -177,16 +179,14 @@ enum ixgbe_media_type ixgbe_get_media_type_X540(struct ixgbe_hw *hw) * ixgbe_setup_mac_link_X540 - Sets the auto advertised capabilities * @hw: pointer to hardware structure * @speed: new link speed - * @autoneg: TRUE if autonegotiation enabled * @autoneg_wait_to_complete: TRUE when waiting for completion is needed **/ s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, - ixgbe_link_speed speed, bool autoneg, + ixgbe_link_speed speed, bool autoneg_wait_to_complete) { DEBUGFUNC("ixgbe_setup_mac_link_X540"); - return hw->phy.ops.setup_link_speed(hw, speed, autoneg, - autoneg_wait_to_complete); + return hw->phy.ops.setup_link_speed(hw, speed, autoneg_wait_to_complete); } /** @@ -227,7 +227,8 @@ mac_reset_top: if (ctrl & IXGBE_CTRL_RST_MASK) { status = IXGBE_ERR_RESET_FAILED; - DEBUGOUT("Reset polling failed to complete.\n"); + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "Reset polling failed to complete.\n"); } msec_delay(100); @@ -373,12 +374,13 @@ s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data) DEBUGFUNC("ixgbe_read_eerd_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == - IXGBE_SUCCESS) + IXGBE_SUCCESS) { status = ixgbe_read_eerd_generic(hw, offset, data); - else + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + } else { status = IXGBE_ERR_SWFW_SYNC; + } - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } @@ -398,13 +400,14 @@ s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw, DEBUGFUNC("ixgbe_read_eerd_buffer_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == - IXGBE_SUCCESS) + IXGBE_SUCCESS) { status = ixgbe_read_eerd_buffer_generic(hw, offset, words, data); - else + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + } else { status = IXGBE_ERR_SWFW_SYNC; + } - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } @@ -422,12 +425,13 @@ s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data) DEBUGFUNC("ixgbe_write_eewr_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == - IXGBE_SUCCESS) + IXGBE_SUCCESS) { status = ixgbe_write_eewr_generic(hw, offset, data); - else + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + } else { status = IXGBE_ERR_SWFW_SYNC; + } - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } @@ -447,13 +451,14 @@ s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw, DEBUGFUNC("ixgbe_write_eewr_buffer_X540"); if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == - IXGBE_SUCCESS) + IXGBE_SUCCESS) { status = ixgbe_write_eewr_buffer_generic(hw, offset, words, data); - else + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + } else { status = IXGBE_ERR_SWFW_SYNC; + } - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); return status; } @@ -579,17 +584,20 @@ s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, * Verify read checksum from EEPROM is the same as * calculated checksum */ - if (read_checksum != checksum) + if (read_checksum != checksum) { status = IXGBE_ERR_EEPROM_CHECKSUM; + ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE, + "Invalid EEPROM checksum"); + } /* If the user cares, return the calculated checksum */ if (checksum_val) *checksum_val = checksum; + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); } else { status = IXGBE_ERR_SWFW_SYNC; } - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); out: return status; } @@ -630,14 +638,13 @@ s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM, checksum); - if (status == IXGBE_SUCCESS) - status = ixgbe_update_flash_X540(hw); - else + if (status == IXGBE_SUCCESS) + status = ixgbe_update_flash_X540(hw); + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); + } else { status = IXGBE_ERR_SWFW_SYNC; } - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM); - return status; } @@ -648,7 +655,7 @@ s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw) * Set FLUP (bit 23) of the EEC register to instruct Hardware to copy * EEPROM from shadow RAM to the flash device. **/ -static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) +s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) { u32 flup; s32 status = IXGBE_ERR_EEPROM; @@ -670,7 +677,7 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw) else DEBUGOUT("Flash update time out\n"); - if (hw->revision_id == 0) { + if (hw->mac.type == ixgbe_mac_X540 && hw->revision_id == 0) { flup = IXGBE_READ_REG(hw, IXGBE_EEC); if (flup & IXGBE_EEC_SEC1VAL) { @@ -711,6 +718,11 @@ static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw) } usec_delay(5); } + + if (i == IXGBE_FLUDONE_ATTEMPTS) + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "Flash update status polling timed out"); + return status; } @@ -772,11 +784,13 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) /* Failed to get SW only semaphore */ if (swmask == IXGBE_GSSR_SW_MNG_SM) { ret_val = IXGBE_ERR_SWFW_SYNC; + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "Failed to get SW only semaphore"); goto out; } /* If the resource is not released by the FW/HW the SW can assume that - * the FW/HW malfunctions. In that case the SW should sets the SW bit(s) + * the FW/HW malfunctions. In that case the SW should set the SW bit(s) * of the requested resource(s) while ignoring the corresponding FW/HW * bits in the SW_FW_SYNC register. */ @@ -792,6 +806,17 @@ s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask) ixgbe_release_swfw_sync_semaphore(hw); msec_delay(5); } + /* If the resource is not released by other SW the SW can assume that + * the other SW malfunctions. In that case the SW should clear all SW + * flags that it does not own and then repeat the whole process once + * again. + */ + else if (swfw_sync & swmask) { + ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM | + IXGBE_GSSR_PHY0_SM | IXGBE_GSSR_PHY1_SM | + IXGBE_GSSR_MAC_CSR_SM); + ret_val = IXGBE_ERR_SWFW_SYNC; + } out: return ret_val; @@ -866,14 +891,15 @@ static s32 ixgbe_get_swfw_sync_semaphore(struct ixgbe_hw *hw) * was not granted because we don't have access to the EEPROM */ if (i >= timeout) { - DEBUGOUT("REGSMP Software NVM semaphore not " - "granted.\n"); + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "REGSMP Software NVM semaphore not granted.\n"); ixgbe_release_swfw_sync_semaphore(hw); status = IXGBE_ERR_EEPROM; } } else { - DEBUGOUT("Software semaphore SMBI between device drivers " - "not granted.\n"); + ERROR_REPORT1(IXGBE_ERROR_POLLING, + "Software semaphore SMBI between device drivers " + "not granted.\n"); } return status; @@ -973,3 +999,4 @@ s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index) return IXGBE_SUCCESS; } + diff --git a/sys/dev/netif/ixgbe/ixgbe_x540.h b/sys/dev/netif/ix/ixgbe_x540.h similarity index 94% rename from sys/dev/netif/ixgbe/ixgbe_x540.h rename to sys/dev/netif/ix/ixgbe_x540.h index 7e393d056d..c86048b0ba 100644 --- a/sys/dev/netif/ixgbe/ixgbe_x540.h +++ b/sys/dev/netif/ix/ixgbe_x540.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright (c) 2001-2012, Intel Corporation + Copyright (c) 2001-2013, Intel Corporation All rights reserved. Redistribution and use in source and binary forms, with or without @@ -30,7 +30,7 @@ POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ -/*$FreeBSD: src/sys/dev/ixgbe/ixgbe_x540.h,v 1.1 2012/01/30 16:42:02 jfv Exp $*/ +/*$FreeBSD$*/ #ifndef _IXGBE_X540_H_ #define _IXGBE_X540_H_ @@ -41,7 +41,7 @@ s32 ixgbe_get_link_capabilities_X540(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg); enum ixgbe_media_type ixgbe_get_media_type_X540(struct ixgbe_hw *hw); s32 ixgbe_setup_mac_link_X540(struct ixgbe_hw *hw, ixgbe_link_speed speed, - bool autoneg, bool link_up_wait_to_complete); + bool link_up_wait_to_complete); s32 ixgbe_reset_hw_X540(struct ixgbe_hw *hw); s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw); u32 ixgbe_get_supported_physical_layer_X540(struct ixgbe_hw *hw); @@ -56,6 +56,7 @@ s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw, u16 offset, u16 words, s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw); s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw, u16 *checksum_val); u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw); +s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw); s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask); void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask); @@ -63,3 +64,4 @@ void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask); s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index); s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index); #endif /* _IXGBE_X540_H_ */ + diff --git a/sys/dev/netif/ixgbe/LICENSE b/sys/dev/netif/ixgbe/LICENSE deleted file mode 100644 index b2cee604ff..0000000000 --- a/sys/dev/netif/ixgbe/LICENSE +++ /dev/null @@ -1,33 +0,0 @@ -/****************************************************************************** - - Copyright (c) 2001-2011, 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/LICENSE,v 1.5 2011/06/02 00:34:57 jfv Exp $*/ diff --git a/sys/dev/netif/ixgbe/Makefile b/sys/dev/netif/ixgbe/Makefile deleted file mode 100644 index b616f45a7f..0000000000 --- a/sys/dev/netif/ixgbe/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -#$FreeBSD: src/sys/modules/ixgbe/Makefile,v 1.12 2012/05/30 13:55:43 uqs Exp $ - -.include - -KMOD = if_ixgbe -SRCS = device_if.h bus_if.h pci_if.h -SRCS += opt_inet.h opt_inet6.h -SRCS += ixgbe.c #ixv.c -# Shared source -SRCS += ixgbe_common.c ixgbe_api.c ixgbe_phy.c ixgbe_mbx.c ixgbe_vf.c -SRCS += ixgbe_82599.c ixgbe_82598.c ixgbe_x540.c -#CFLAGS+=-DIXGBE_FDIR - -.if !defined(BUILDING_WITH_KERNEL) -opt_inet.h: - @echo "#define INET 1" > ${.TARGET} - -opt_inet6.h: - @echo "#define INET6 1" > ${.TARGET} -.endif - -.include diff --git a/sys/dev/netif/ixgbe/README b/sys/dev/netif/ixgbe/README deleted file mode 100644 index 5d64d06a21..0000000000 --- a/sys/dev/netif/ixgbe/README +++ /dev/null @@ -1,323 +0,0 @@ -FreeBSD Driver for Intel(R) Ethernet 10 Gigabit PCI Express Server Adapters -============================================================================ -/*$FreeBSD: src/sys/dev/ixgbe/README,v 1.3 2011/06/02 00:34:57 jfv Exp $*/ - -November 12, 2010 - - -Contents -======== - -- Overview -- Supported Adapters -- Building and Installation -- Additional Configurations and Tuning -- Known Limitations - - -Overview -======== - -This file describes the FreeBSD* driver for the Intel(R) Ethernet 10 Gigabit -Family of Adapters. Driver has been developed for use with FreeBSD 7.2 or later. - -For questions related to hardware requirements, refer to the documentation -supplied with your Intel 10GbE adapter. All hardware requirements listed -apply to use with FreeBSD. - - -Supported Adapters -================== - -The driver in this release is compatible with 82598 and 82599-based Intel -Network Connections. - -SFP+ Devices with Pluggable Optics ----------------------------------- - -82599-BASED ADAPTERS - -NOTE: If your 82599-based Intel(R) Ethernet Network Adapter came with Intel -optics, or is an Intel(R) Ethernet Server Adapter X520-2, then it only supports -Intel optics and/or the direct attach cables listed below. - -When 82599-based SFP+ devices are connected back to back, they should be set to -the same Speed setting via Ethtool. Results may vary if you mix speed settings. - -Supplier Type Part Numbers - -SR Modules -Intel DUAL RATE 1G/10G SFP+ SR (bailed) FTLX8571D3BCV-IT -Intel DUAL RATE 1G/10G SFP+ SR (bailed) AFBR-703SDZ-IN2 -Intel DUAL RATE 1G/10G SFP+ SR (bailed) AFBR-703SDDZ-IN1 -LR Modules -Intel DUAL RATE 1G/10G SFP+ LR (bailed) FTLX1471D3BCV-IT -Intel DUAL RATE 1G/10G SFP+ LR (bailed) AFCT-701SDZ-IN2 -Intel DUAL RATE 1G/10G SFP+ LR (bailed) AFCT-701SDDZ-IN1 - -The following is a list of 3rd party SFP+ modules and direct attach cables that -have received some testing. Not all modules are applicable to all devices. - -Supplier Type Part Numbers - -Finisar SFP+ SR bailed, 10g single rate FTLX8571D3BCL -Avago SFP+ SR bailed, 10g single rate AFBR-700SDZ -Finisar SFP+ LR bailed, 10g single rate FTLX8571D3BCV-IT - -Finisar DUAL RATE 1G/10G SFP+ SR (No Bail) FTLX8571D3QCV-IT -Avago DUAL RATE 1G/10G SFP+ SR (No Bail) AFBR-703SDZ-IN1 -Finisar DUAL RATE 1G/10G SFP+ LR (No Bail) FTLX1471D3QCV-IT -Avago DUAL RATE 1G/10G SFP+ LR (No Bail) AFCT-701SDZ-IN1 -Finistar 1000BASE-T SFP FCLF8522P2BTL -Avago 1000BASE-T SFP ABCU-5710RZ - -82599-based adapters support all passive and active limiting direct attach -cables that comply with SFF-8431 v4.1 and SFF-8472 v10.4 specifications. - -Laser turns off for SFP+ when ifconfig down --------------------------------------------------------- -"ifconfig down" turns off the laser for 82599-based SFP+ fiber adapters. -"ifconfig up" turns on the later. - -82598-BASED ADAPTERS - -NOTES for 82598-Based Adapters: -- Intel(R) Ethernet Network Adapters that support removable optical modules - only support their original module type (i.e., the Intel(R) 10 Gigabit SR - Dual Port Express Module only supports SR optical modules). If you plug - in a different type of module, the driver will not load. -- Hot Swapping/hot plugging optical modules is not supported. -- Only single speed, 10 gigabit modules are supported. -- LAN on Motherboard (LOMs) may support DA, SR, or LR modules. Other module - types are not supported. Please see your system documentation for details. - -The following is a list of 3rd party SFP+ modules and direct attach cables that have -received some testing. Not all modules are applicable to all devices. - -Supplier Type Part Numbers - -Finisar SFP+ SR bailed, 10g single rate FTLX8571D3BCL -Avago SFP+ SR bailed, 10g single rate AFBR-700SDZ -Finisar SFP+ LR bailed, 10g single rate FTLX1471D3BCL - -82598-based adapters support all passive direct attach cables that comply -with SFF-8431 v4.1 and SFF-8472 v10.4 specifications. Active direct attach -cables are not supported. - -Third party optic modules and cables referred to above are listed only for the -purpose of highlighting third party specifications and potential compatibility, -and are not recommendations or endorsements or sponsorship of any third party's -product by Intel. Intel is not endorsing or promoting products made by any -third party and the third party reference is provided only to share information -regarding certain optic modules and cables with the above specifications. There -may be other manufacturers or suppliers, producing or supplying optic modules -and cables with similar or matching descriptions. Customers must use their own -discretion and diligence to purchase optic modules and cables from any third -party of their choice. Customer are solely responsible for assessing the -suitability of the product and/or devices and for the selection of the vendor -for purchasing any product. INTEL ASSUMES NO LIABILITY WHATSOEVER, AND INTEL -DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY, RELATING TO SALE AND/OR USE OF -SUCH THIRD PARTY PRODUCTS OR SELECTION OF VENDOR BY CUSTOMERS. - -Configuration and Tuning -======================== - -The driver supports Transmit/Receive Checksum Offload and Jumbo Frames on -all 10 Gigabit adapters. - - Jumbo Frames - ------------ - To enable Jumbo Frames, use the ifconfig utility to increase the MTU - beyond 1500 bytes. - - NOTES: - - - The Jumbo Frames setting on the switch must be set to at least - 22 bytes larger than that of the adapter. - - - There are known performance issues with this driver when running - UDP traffic with Jumbo Frames. - - The Jumbo Frames MTU range for Intel Adapters is 1500 to 16114. The default - MTU range is 1500. To modify the setting, enter the following: - - ifconfig ix mtu 9000 - - To confirm an interface's MTU value, use the ifconfig command. To confirm - the MTU used between two specific devices, use: - - route get - - VLANs - ----- - To create a new VLAN pseudo-interface: - - ifconfig create - - To associate the VLAN pseudo-interface with a physical interface and - assign a VLAN ID, IP address, and netmask: - - ifconfig netmask vlan - vlandev - - Example: - - ifconfig vlan10 10.0.0.1 netmask 255.255.255.0 vlan 10 vlandev ixgbe0 - - In this example, all packets will be marked on egress with 802.1Q VLAN - tags, specifying a VLAN ID of 10. - - To remove a VLAN pseudo-interface: - - ifconfig destroy - - - Checksum Offload - ---------------- - - Checksum offloading supports both TCP and UDP packets and is - supported for both transmit and receive. - - Checksum offloading can be enabled or disabled using ifconfig. - Both transmit and receive offloading will be either enabled or - disabled together. You cannot enable/disable one without the other. - - To enable checksum offloading: - - ifconfig rxcsum - - To disable checksum offloading: - - ifconfig -rxcsum - - To confirm the current setting: - - ifconfig - - - TSO - --- - - TSO is enabled by default. - - To disable: - - ifconfig -tso - - To re-enable: - - ifconfig tso - - LRO - --- - - Large Receive Offload is available in the driver; it is on by default. - It can be disabled by using: - ifconfig -lro - To enable: - ifconfig lro - - - Important system configuration changes: - --------------------------------------- - - When there is a choice run on a 64bit OS rather than 32, it makes a - significant difference in improvement. - - The default scheduler SCHED_4BSD is not smart about SMP locality issues. - Significant improvement can be achieved by switching to the ULE scheduler. - - This is done by changing the entry in the config file from SCHED_4BSD to - SCHED_ULE. Note that this is only advisable on FreeBSD 7, on 6.X there have - been stability problems with ULE. - - The interface can generate high number of interrupts. To avoid running - into the limit set by the kernel, adjust hw.intr_storm_threshold - setting using sysctl: - - sysctl hw.intr_storm_threshold=9000 (the default is 1000) - - For this change to take effect on boot, edit /etc/sysctl.conf and add the - line: - hw.intr_storm_threshold=9000 - - If you still see Interrupt Storm detected messages, increase the limit to a - higher number. - - Best throughput results are seen with a large MTU; use 9000 if possible. - - The default number of descriptors is 1024, increasing this to 2K or even - 4K may improve performance in some workloads, but change carefully. - - -Known Limitations -================= - -For known hardware and troubleshooting issues, refer to the following website. - - http://support.intel.com/support/go/network/adapter/home.htm - -Either select the link for your adapter or perform a search for the adapter -number. The adapter's page lists many issues. For a complete list of hardware -issues download your adapter's user guide and read the Release Notes. - - UDP stress test with 10GbE driver - --------------------------------- - Under small packets UDP stress test with 10GbE driver, the FreeBSD system - will drop UDP packets due to the fullness of socket buffers. You may want - to change the driver's Flow Control variables to the minimum value for - controlling packet reception. - - Attempting to configure larger MTUs with a large numbers of processors may - generate the error message "ix0:could not setup receive structures" - -------------------------------------------------------------------------- - When using the ixgbe driver with RSS autoconfigured based on the number of - cores (the default setting) and that number is larger than 4, increase the - memory resources allocated for the mbuf pool as follows: - - Add to the sysctl.conf file for the system: - - kern.ipc.nmbclusters=262144 - kern.ipc.nmbjumbop=262144 - - Lower than expected performance on dual port 10GbE devices - ---------------------------------------------------------- - Some PCI-E x8 slots are actually configured as x4 slots. These slots have - insufficient bandwidth for full 10Gbe line rate with dual port 10GbE devices. - The driver can detect this situation and will write the following message in - the system log: "PCI-Express bandwidth available for this card is not - sufficient for optimal performance. For optimal performance a x8 PCI-Express - slot is required." - - If this error occurs, moving your adapter to a true x8 slot will resolve the - issue. - - - -Support -======= - -For general information and support, go to the Intel support website at: - - www.intel.com/support/ - -If an issue is identified with the released source code on the supported -kernel with a supported adapter, email the specific information related to -the issue to freebsd@intel.com - - - -License -======= - -This software program is released under the terms of a license agreement -between you ('Licensee') and Intel. Do not use or load this software or any -associated materials (collectively, the 'Software') until you have carefully -read the full terms and conditions of the LICENSE located in this software -package. By loading or using the Software, you agree to the terms of this -Agreement. If you do not agree with the terms of this Agreement, do not -install or use the Software. - -* Other names and brands may be claimed as the property of others. - - diff --git a/sys/dev/netif/ixgbe/ixgbe.c b/sys/dev/netif/ixgbe/ixgbe.c deleted file mode 100644 index db1ca767da..0000000000 --- a/sys/dev/netif/ixgbe/ixgbe.c +++ /dev/null @@ -1,5697 +0,0 @@ -/****************************************************************************** - - Copyright (c) 2001-2012, 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.70 2012/07/05 20:51:44 jfv Exp $*/ - -#include "opt_inet.h" -#include "opt_inet6.h" - -#include "ixgbe.h" - -/********************************************************************* - * Set this to one to display debug statistics - *********************************************************************/ -int ixgbe_display_debug_stats = 0; - -/********************************************************************* - * Driver version - *********************************************************************/ -char ixgbe_driver_version[] = "2.4.8"; - -/********************************************************************* - * PCI Device ID Table - * - * Used by probe to select devices to load on - * Last field stores an index into ixgbe_strings - * Last entry must be all 0s - * - * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } - *********************************************************************/ - -static ixgbe_vendor_info_t ixgbe_vendor_info_array[] = -{ - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_DA_DUAL_PORT, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_CX4_DUAL_PORT, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_XF_LR, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_SFP_LOM, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_KX4_MEZZ, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_XAUI_LOM, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_CX4, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_T3_LOM, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_COMBO_BACKPLANE, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_BACKPLANE_FCOE, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_SF2, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_SFP_FCOE, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599EN_SFP, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T1, 0, 0, 0}, - {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540T, 0, 0, 0}, - /* required last entry */ - {0, 0, 0, 0, 0} -}; - -/********************************************************************* - * Table of branding strings - *********************************************************************/ - -static char *ixgbe_strings[] = { - "Intel(R) PRO/10GbE PCI-Express Network Driver" -}; - -/********************************************************************* - * Function prototypes - *********************************************************************/ -static int ixgbe_probe(device_t); -static int ixgbe_attach(device_t); -static int ixgbe_detach(device_t); -static int ixgbe_shutdown(device_t); -static void ixgbe_start(struct ifnet *, struct ifaltq_subque *); -static void ixgbe_start_locked(struct tx_ring *, struct ifnet *); -#if 0 /* __FreeBSD_version >= 800000 */ -static int ixgbe_mq_start(struct ifnet *, struct mbuf *); -static int ixgbe_mq_start_locked(struct ifnet *, - struct tx_ring *, struct mbuf *); -static void ixgbe_qflush(struct ifnet *); -#endif -static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *); -static void ixgbe_init(void *); -static void ixgbe_init_locked(struct adapter *); -static void ixgbe_stop(void *); -static void ixgbe_media_status(struct ifnet *, struct ifmediareq *); -static int ixgbe_media_change(struct ifnet *); -static void ixgbe_identify_hardware(struct adapter *); -static int ixgbe_allocate_pci_resources(struct adapter *); -static int ixgbe_allocate_msix(struct adapter *); -static int ixgbe_allocate_legacy(struct adapter *); -static int ixgbe_allocate_queues(struct adapter *); -static int ixgbe_setup_msix(struct adapter *); -static void ixgbe_free_pci_resources(struct adapter *); -static void ixgbe_local_timer(void *); -static int ixgbe_setup_interface(device_t, struct adapter *); -static void ixgbe_config_link(struct adapter *); - -static int ixgbe_allocate_transmit_buffers(struct tx_ring *); -static int ixgbe_setup_transmit_structures(struct adapter *); -static void ixgbe_setup_transmit_ring(struct tx_ring *); -static void ixgbe_initialize_transmit_units(struct adapter *); -static void ixgbe_free_transmit_structures(struct adapter *); -static void ixgbe_free_transmit_buffers(struct tx_ring *); - -static int ixgbe_allocate_receive_buffers(struct rx_ring *); -static int ixgbe_setup_receive_structures(struct adapter *); -static int ixgbe_setup_receive_ring(struct rx_ring *); -static void ixgbe_initialize_receive_units(struct adapter *); -static void ixgbe_free_receive_structures(struct adapter *); -static void ixgbe_free_receive_buffers(struct rx_ring *); -#if 0 /* NET_LRO */ -static void ixgbe_setup_hw_rsc(struct rx_ring *); -#endif - -static void ixgbe_enable_intr(struct adapter *); -static void ixgbe_disable_intr(struct adapter *); -static void ixgbe_update_stats_counters(struct adapter *); -static void ixgbe_txeof(struct tx_ring *); -static void ixgbe_rxeof(struct ix_queue *, int); -static void ixgbe_rx_checksum(u32, struct mbuf *, u32); -static void ixgbe_set_promisc(struct adapter *); -static void ixgbe_set_multi(struct adapter *); -static void ixgbe_update_link_status(struct adapter *); -static void ixgbe_refresh_mbufs(struct rx_ring *, int); -static int ixgbe_xmit(struct tx_ring *, struct mbuf **); -static int ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS); -static int ixgbe_set_advertise(SYSCTL_HANDLER_ARGS); -static int ixgbe_set_thermal_test(SYSCTL_HANDLER_ARGS); -static int ixgbe_dma_malloc(struct adapter *, bus_size_t, - struct ixgbe_dma_alloc *, int); -static void ixgbe_dma_free(struct adapter *, struct ixgbe_dma_alloc *); -static void ixgbe_add_rx_process_limit(struct adapter *, const char *, - const char *, int *, int); -static bool ixgbe_tx_ctx_setup(struct tx_ring *, struct mbuf *); -static bool ixgbe_tso_setup(struct tx_ring *, struct mbuf *, u32 *, u32 *); -static int ixgbe_tso_pullup(struct tx_ring *, struct mbuf **); -static void ixgbe_add_sysctl(struct adapter *); -static void ixgbe_set_eitr(struct adapter *, int, int); -static int ixgbe_sysctl_intr_rate(SYSCTL_HANDLER_ARGS); -static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); -static void ixgbe_configure_ivars(struct adapter *); -static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); - -static void ixgbe_setup_vlan_hw_support(struct adapter *); -static void ixgbe_register_vlan(void *, struct ifnet *, u16); -static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); - -static void ixgbe_add_hw_stats(struct adapter *adapter); - -static __inline void ixgbe_rx_discard(struct rx_ring *, int); -static __inline void ixgbe_rx_input(struct rx_ring *, struct ifnet *, - struct mbuf *, u32); - -/* Support for pluggable optic modules */ -static bool ixgbe_sfp_probe(struct adapter *); -static void ixgbe_setup_optics(struct adapter *); - -/* Legacy (single vector interrupt handler */ -static void ixgbe_legacy_irq(void *); - -/* The MSI/X Interrupt handlers */ -static void ixgbe_msix_que(void *); -static void ixgbe_msix_link(void *); - -/* Deferred interrupt tasklets */ -static void ixgbe_handle_msf(void *, int); -static void ixgbe_handle_mod(void *, int); - -#ifdef IXGBE_FDIR -static void ixgbe_atr(struct tx_ring *, struct mbuf *); -static void ixgbe_reinit_fdir(void *, int); -#endif - -/********************************************************************* - * FreeBSD Device Interface Entry Points - *********************************************************************/ - -static device_method_t ixgbe_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ixgbe_probe), - DEVMETHOD(device_attach, ixgbe_attach), - DEVMETHOD(device_detach, ixgbe_detach), - DEVMETHOD(device_shutdown, ixgbe_shutdown), - DEVMETHOD_END -}; - -static driver_t ixgbe_driver = { - "ix", ixgbe_methods, sizeof(struct adapter), -}; - -devclass_t ixgbe_devclass; -DRIVER_MODULE(ixgbe, pci, ixgbe_driver, ixgbe_devclass, NULL, NULL); - -MODULE_DEPEND(ixgbe, pci, 1, 1, 1); -MODULE_DEPEND(ixgbe, ether, 1, 1, 1); - -/* -** TUNEABLE PARAMETERS: -*/ - -/* How many packets rxeof tries to clean at a time */ -static int ixgbe_rx_process_limit = 128; -TUNABLE_INT("hw.ixgbe.rx_process_limit", &ixgbe_rx_process_limit); - -/* -** Smart speed setting, default to on -** this only works as a compile option -** right now as its during attach, set -** this to 'ixgbe_smart_speed_off' to -** disable. -*/ -static int ixgbe_smart_speed = ixgbe_smart_speed_on; - -static int ixgbe_msi_enable = 1; -TUNABLE_INT("hw.ixgbe.msi.enable", &ixgbe_msi_enable); - -/* - * MSIX should be the default for best performance, - * but this allows it to be forced off for testing. - */ -static int ixgbe_enable_msix = 1; -TUNABLE_INT("hw.ixgbe.enable_msix", &ixgbe_enable_msix); - -/* - * Header split: this causes the hardware to DMA - * the header into a separate mbuf from the payload, - * it can be a performance win in some workloads, but - * in others it actually hurts, its off by default. - */ -static int ixgbe_header_split = FALSE; -TUNABLE_INT("hw.ixgbe.hdr_split", &ixgbe_header_split); - -/* - * Number of Queues, can be set to 0, - * it then autoconfigures based on the - * number of cpus with a max of 8. This - * can be overriden manually here. - */ -static int ixgbe_num_queues = 0; -TUNABLE_INT("hw.ixgbe.num_queues", &ixgbe_num_queues); - -/* -** Number of TX descriptors per ring, -** setting higher than RX as this seems -** the better performing choice. -*/ -static int ixgbe_txd = PERFORM_TXD; -TUNABLE_INT("hw.ixgbe.txd", &ixgbe_txd); - -/* Number of RX descriptors per ring */ -static int ixgbe_rxd = PERFORM_RXD; -TUNABLE_INT("hw.ixgbe.rxd", &ixgbe_rxd); - -/* Keep running tab on them for sanity check */ -static int ixgbe_total_ports; - -#ifdef IXGBE_FDIR -/* -** For Flow Director: this is the -** number of TX packets we sample -** for the filter pool, this means -** every 20th packet will be probed. -** -** This feature can be disabled by -** setting this to 0. -*/ -static int atr_sample_rate = 20; -/* -** Flow Director actually 'steals' -** part of the packet buffer as its -** filter pool, this variable controls -** how much it uses: -** 0 = 64K, 1 = 128K, 2 = 256K -*/ -static int fdir_pballoc = 1; -#endif - -#ifdef DEV_NETMAP -/* - * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to - * be a reference on how to implement netmap support in a driver. - * Additional comments are in ixgbe_netmap.h . - * - * contains functions for netmap support - * that extend the standard driver. - */ -#include -#endif /* DEV_NETMAP */ - -/********************************************************************* - * Device identification routine - * - * ixgbe_probe determines if the driver should be loaded on - * adapter based on PCI vendor/device id of the adapter. - * - * return BUS_PROBE_DEFAULT on success, positive on failure - *********************************************************************/ - -static int -ixgbe_probe(device_t dev) -{ - ixgbe_vendor_info_t *ent; - - u16 pci_vendor_id = 0; - u16 pci_device_id = 0; - u16 pci_subvendor_id = 0; - u16 pci_subdevice_id = 0; - char adapter_name[256]; - - INIT_DEBUGOUT("ixgbe_probe: begin"); - - pci_vendor_id = pci_get_vendor(dev); - if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) - return (ENXIO); - - pci_device_id = pci_get_device(dev); - pci_subvendor_id = pci_get_subvendor(dev); - pci_subdevice_id = pci_get_subdevice(dev); - - ent = ixgbe_vendor_info_array; - while (ent->vendor_id != 0) { - if ((pci_vendor_id == ent->vendor_id) && - (pci_device_id == ent->device_id) && - - ((pci_subvendor_id == ent->subvendor_id) || - (ent->subvendor_id == 0)) && - - ((pci_subdevice_id == ent->subdevice_id) || - (ent->subdevice_id == 0))) { - ksprintf(adapter_name, "%s, Version - %s", - ixgbe_strings[ent->index], - ixgbe_driver_version); - device_set_desc_copy(dev, adapter_name); - ++ixgbe_total_ports; - return (BUS_PROBE_DEFAULT); - } - ent++; - } - return (ENXIO); -} - -/********************************************************************* - * 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 - *********************************************************************/ - -static int -ixgbe_attach(device_t dev) -{ - struct adapter *adapter; - struct ixgbe_hw *hw; - int error = 0; - u16 csum; - u32 ctrl_ext; - - INIT_DEBUGOUT("ixgbe_attach: begin"); - - if (resource_disabled("ixgbe", device_get_unit(dev))) { - device_printf(dev, "Disabled by device hint\n"); - return (ENXIO); - } - - /* Allocate, clear, and link in our adapter structure */ - adapter = device_get_softc(dev); - adapter->dev = adapter->osdep.dev = dev; - hw = &adapter->hw; - - /* Core Lock Init*/ - IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); - - /* Set up the timer callout */ - callout_init_mp(&adapter->timer); - - /* Determine hardware revision */ - ixgbe_identify_hardware(adapter); - - /* Enable bus mastering */ - pci_enable_busmaster(dev); - - /* Do base PCI setup - map BAR0 */ - if (ixgbe_allocate_pci_resources(adapter)) { - device_printf(dev, "Allocation of PCI resources failed\n"); - error = ENXIO; - goto err_out; - } - - /* Do descriptor calc and sanity checks */ - if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || - ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { - device_printf(dev, "TXD config issue, using default!\n"); - adapter->num_tx_desc = DEFAULT_TXD; - } else - adapter->num_tx_desc = ixgbe_txd; - - /* - ** With many RX rings it is easy to exceed the - ** system mbuf allocation. Tuning nmbclusters - ** can alleviate this. - */ - if (nmbclusters > 0 ) { - int s; - s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; - if (s > nmbclusters) { - device_printf(dev, "RX Descriptors exceed " - "system mbuf max, using default instead!\n"); - ixgbe_rxd = DEFAULT_RXD; - } - } - - if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || - ixgbe_rxd < MIN_TXD || ixgbe_rxd > MAX_TXD) { - device_printf(dev, "RXD config issue, using default!\n"); - adapter->num_rx_desc = DEFAULT_RXD; - } else - adapter->num_rx_desc = ixgbe_rxd; - - /* Allocate our TX/RX Queues */ - if (ixgbe_allocate_queues(adapter)) { - error = ENOMEM; - goto err_out; - } - - /* Allocate multicast array memory. */ - adapter->mta = kmalloc(sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * - MAX_NUM_MULTICAST_ADDRESSES, M_DEVBUF, M_NOWAIT); - if (adapter->mta == NULL) { - device_printf(dev, "Can not allocate multicast setup array\n"); - error = ENOMEM; - goto err_late; - } - - /* Initialize the shared code */ - error = ixgbe_init_shared_code(hw); - if (error == IXGBE_ERR_SFP_NOT_PRESENT) { - /* - ** No optics in this port, set up - ** so the timer routine will probe - ** for later insertion. - */ - adapter->sfp_probe = TRUE; - error = 0; - } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { - device_printf(dev,"Unsupported SFP+ module detected!\n"); - error = EIO; - goto err_late; - } else if (error) { - device_printf(dev,"Unable to initialize the shared code\n"); - error = EIO; - goto err_late; - } - - /* Make sure we have a good EEPROM before we read from it */ - if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { - device_printf(dev,"The EEPROM Checksum Is Not Valid\n"); - error = EIO; - goto err_late; - } - - error = ixgbe_init_hw(hw); - switch (error) { - case IXGBE_ERR_EEPROM_VERSION: - device_printf(dev, "This device is a pre-production adapter/" - "LOM. Please be aware there may be issues associated " - "with your hardware.\n If you are experiencing problems " - "please contact your Intel or hardware representative " - "who provided you with this hardware.\n"); - break; - case IXGBE_ERR_SFP_NOT_SUPPORTED: - device_printf(dev,"Unsupported SFP+ Module\n"); - error = EIO; - device_printf(dev,"Hardware Initialization Failure\n"); - goto err_late; - case IXGBE_ERR_SFP_NOT_PRESENT: - device_printf(dev,"No SFP+ Module found\n"); - /* falls thru */ - default: - break; - } - - /* Detect and set physical type */ - ixgbe_setup_optics(adapter); - - if ((adapter->msix > 1) && (ixgbe_enable_msix)) { - adapter->intr_type = PCI_INTR_TYPE_MSIX; - error = ixgbe_allocate_msix(adapter); - } else { - error = ixgbe_allocate_legacy(adapter); - } - if (error) - goto err_late; - - /* Setup OS specific network interface */ - if (ixgbe_setup_interface(dev, adapter) != 0) - goto err_late; - - /* Add sysctl tree */ - ixgbe_add_sysctl(adapter); - - /* Initialize statistics */ - ixgbe_update_stats_counters(adapter); - - /* Register for VLAN events */ - adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, - ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); - adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, - ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); - - /* Print PCIE bus type/speed/width info */ - ixgbe_get_bus_info(hw); - device_printf(dev,"PCI Express Bus: Speed %s %s\n", - ((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s": - (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5Gb/s":"Unknown"), - (hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : - (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : - (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : - ("Unknown")); - - if ((hw->bus.width <= ixgbe_bus_width_pcie_x4) && - (hw->bus.speed == ixgbe_bus_speed_2500)) { - device_printf(dev, "PCI-Express bandwidth available" - " for this card\n is not sufficient for" - " optimal performance.\n"); - device_printf(dev, "For optimal performance a x8 " - "PCIE, or x4 PCIE 2 slot is required.\n"); - } - - /* let hardware know driver is loaded */ - ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); - ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; - IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); - - ixgbe_add_hw_stats(adapter); - -#ifdef DEV_NETMAP - ixgbe_netmap_attach(adapter); -#endif /* DEV_NETMAP */ - INIT_DEBUGOUT("ixgbe_attach: end"); - return (0); -err_late: - ixgbe_free_transmit_structures(adapter); - ixgbe_free_receive_structures(adapter); -err_out: - if (adapter->ifp != NULL) - if_free(adapter->ifp); - ixgbe_free_pci_resources(adapter); - kfree(adapter->mta, M_DEVBUF); - return (error); - -} - -/********************************************************************* - * Device removal routine - * - * The detach entry point is called when the driver is being removed. - * This routine stops the adapter and deallocates all the resources - * that were allocated for driver operation. - * - * return 0 on success, positive on failure - *********************************************************************/ - -static int -ixgbe_detach(device_t dev) -{ - struct adapter *adapter = device_get_softc(dev); - u32 ctrl_ext; - - INIT_DEBUGOUT("ixgbe_detach: begin"); - - /* Make sure VLANS are not using driver */ - if (adapter->ifp->if_vlantrunks != NULL) { - device_printf(dev,"Vlan in use, detach first\n"); - return (EBUSY); - } - - IXGBE_CORE_LOCK(adapter); - ixgbe_stop(adapter); - IXGBE_CORE_UNLOCK(adapter); - - /* Drain the Link queue */ - if (adapter->tq) { - taskqueue_drain(adapter->tq, &adapter->mod_task); - taskqueue_drain(adapter->tq, &adapter->msf_task); -#ifdef IXGBE_FDIR - taskqueue_drain(adapter->tq, &adapter->fdir_task); -#endif - taskqueue_free(adapter->tq); - } - - /* let hardware know driver is unloading */ - ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT); - ctrl_ext &= ~IXGBE_CTRL_EXT_DRV_LOAD; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT, ctrl_ext); - - /* Unregister VLAN events */ - if (adapter->vlan_attach != NULL) - EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); - if (adapter->vlan_detach != NULL) - EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); - - ether_ifdetach(adapter->ifp); - callout_stop(&adapter->timer); -#ifdef DEV_NETMAP - netmap_detach(adapter->ifp); -#endif /* DEV_NETMAP */ - ixgbe_free_pci_resources(adapter); - bus_generic_detach(dev); - if_free(adapter->ifp); - - ixgbe_free_transmit_structures(adapter); - ixgbe_free_receive_structures(adapter); - kfree(adapter->mta, M_DEVBUF); - sysctl_ctx_free(&adapter->sysctl_ctx); - - IXGBE_CORE_LOCK_DESTROY(adapter); - return (0); -} - -/********************************************************************* - * - * Shutdown entry point - * - **********************************************************************/ - -static int -ixgbe_shutdown(device_t dev) -{ - struct adapter *adapter = device_get_softc(dev); - IXGBE_CORE_LOCK(adapter); - ixgbe_stop(adapter); - IXGBE_CORE_UNLOCK(adapter); - return (0); -} - - -/********************************************************************* - * 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. - **********************************************************************/ - -static void -ixgbe_start_locked(struct tx_ring *txr, struct ifnet * ifp) -{ - struct mbuf *m_head; - struct adapter *adapter = txr->adapter; - - IXGBE_TX_LOCK_ASSERT(txr); - - if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd)) - return; - - if (!adapter->link_active) { - ifq_purge(&ifp->if_snd); - return; - } - - while (!ifq_is_empty(&ifp->if_snd)) { - if (txr->tx_avail <= IXGBE_QUEUE_MIN_FREE) { - txr->queue_status |= IXGBE_QUEUE_DEPLETED; - break; - } - - m_head = ifq_dequeue(&ifp->if_snd); - if (m_head == NULL) - break; - - if (ixgbe_xmit(txr, &m_head)) { - if (m_head != NULL) - ifq_prepend(&ifp->if_snd, m_head); - if (txr->tx_avail <= IXGBE_QUEUE_MIN_FREE) - txr->queue_status |= IXGBE_QUEUE_DEPLETED; - break; - } - /* Send a copy of the frame to the BPF listener */ - ETHER_BPF_MTAP(ifp, m_head); - - /* Set watchdog on */ - txr->watchdog_time = ticks; - txr->queue_status = IXGBE_QUEUE_WORKING; - - } - return; -} - -/* - * Legacy TX start - called by the stack, this - * always uses the first tx ring, and should - * not be used with multiqueue tx enabled. - */ -static void -ixgbe_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) -{ - struct adapter *adapter = ifp->if_softc; - struct tx_ring *txr = adapter->tx_rings; - - ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); - - if (ifp->if_flags & IFF_RUNNING) { - IXGBE_TX_LOCK(txr); - ixgbe_start_locked(txr, ifp); - IXGBE_TX_UNLOCK(txr); - } - return; -} - -#if 0 /* __FreeBSD_version >= 800000 */ -/* -** Multiqueue Transmit driver -** -*/ -static int -ixgbe_mq_start(struct ifnet *ifp, struct mbuf *m) -{ - struct adapter *adapter = ifp->if_softc; - struct ix_queue *que; - struct tx_ring *txr; - int i = 0, err = 0; - - /* Which queue to use */ - if ((m->m_flags & M_FLOWID) != 0) - i = m->m_pkthdr.flowid % adapter->num_queues; - else - i = curcpu % adapter->num_queues; - - txr = &adapter->tx_rings[i]; - que = &adapter->queues[i]; - - if (((txr->queue_status & IXGBE_QUEUE_DEPLETED) == 0) && - IXGBE_TX_TRYLOCK(txr)) { - err = ixgbe_mq_start_locked(ifp, txr, m); - IXGBE_TX_UNLOCK(txr); - } else { - err = drbr_enqueue(ifp, txr->br, m); - taskqueue_enqueue(que->tq, &que->que_task); - } - - return (err); -} - -static int -ixgbe_mq_start_locked(struct ifnet *ifp, struct tx_ring *txr, struct mbuf *m) -{ - struct adapter *adapter = txr->adapter; - struct mbuf *next; - int enqueued, err = 0; - - if (((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) || - (txr->queue_status == IXGBE_QUEUE_DEPLETED) || - adapter->link_active == 0) { - if (m != NULL) - err = drbr_enqueue(ifp, txr->br, m); - return (err); - } - - enqueued = 0; - if (m == NULL) { - next = drbr_dequeue(ifp, txr->br); - } else if (drbr_needs_enqueue(ifp, txr->br)) { - if ((err = drbr_enqueue(ifp, txr->br, m)) != 0) - return (err); - next = drbr_dequeue(ifp, txr->br); - } else - next = m; - - /* Process the queue */ - while (next != NULL) { - if ((err = ixgbe_xmit(txr, &next)) != 0) { - if (next != NULL) - err = drbr_enqueue(ifp, txr->br, next); - break; - } - enqueued++; - drbr_stats_update(ifp, next->m_pkthdr.len, next->m_flags); - /* Send a copy of the frame to the BPF listener */ - ETHER_BPF_MTAP(ifp, next); - if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) - break; - if (txr->tx_avail < IXGBE_TX_OP_THRESHOLD) - ixgbe_txeof(txr); - if (txr->tx_avail < IXGBE_TX_OP_THRESHOLD) { - txr->queue_status |= IXGBE_QUEUE_DEPLETED; - break; - } - next = drbr_dequeue(ifp, txr->br); - } - - if (enqueued > 0) { - /* Set watchdog on */ - txr->queue_status |= IXGBE_QUEUE_WORKING; - txr->watchdog_time = ticks; - } - - if (txr->tx_avail < IXGBE_TX_CLEANUP_THRESHOLD) - ixgbe_txeof(txr); - - return (err); -} - -/* -** Flush all ring buffers -*/ -static void -ixgbe_qflush(struct ifnet *ifp) -{ - struct adapter *adapter = ifp->if_softc; - struct tx_ring *txr = adapter->tx_rings; - struct mbuf *m; - - for (int i = 0; i < adapter->num_queues; i++, txr++) { - IXGBE_TX_LOCK(txr); - while ((m = buf_ring_dequeue_sc(txr->br)) != NULL) - m_freem(m); - IXGBE_TX_UNLOCK(txr); - } - if_qflush(ifp); -} -#endif /* __FreeBSD_version >= 800000 */ - -/********************************************************************* - * Ioctl entry point - * - * ixgbe_ioctl is called when the user wants to configure the - * interface. - * - * return 0 on success, positive on failure - **********************************************************************/ - -static int -ixgbe_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr) -{ - struct adapter *adapter = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *) data; -#if defined(INET) || defined(INET6) - struct ifaddr *ifa = (struct ifaddr *)data; - bool avoid_reset = FALSE; -#endif - int error = 0; - - switch (command) { - - case SIOCSIFADDR: -#ifdef INET - if (ifa->ifa_addr->sa_family == AF_INET) - avoid_reset = TRUE; -#endif -#ifdef INET6 - if (ifa->ifa_addr->sa_family == AF_INET6) - avoid_reset = TRUE; -#endif -#if defined(INET) || defined(INET6) - /* - ** Calling init results in link renegotiation, - ** so we avoid doing it when possible. - */ - if (avoid_reset) { - ifp->if_flags |= IFF_UP; - if (!(ifp->if_flags & IFF_RUNNING)) - ixgbe_init(adapter); - if (!(ifp->if_flags & IFF_NOARP)) - arp_ifinit(ifp, ifa); - } else - error = ether_ioctl(ifp, command, data); -#endif - break; - case SIOCSIFMTU: - IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); - if (ifr->ifr_mtu > IXGBE_MAX_FRAME_SIZE - ETHER_HDR_LEN) { - error = EINVAL; - } else { - IXGBE_CORE_LOCK(adapter); - ifp->if_mtu = ifr->ifr_mtu; - adapter->max_frame_size = - ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; - ixgbe_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); - } - break; - case SIOCSIFFLAGS: - IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); - IXGBE_CORE_LOCK(adapter); - if (ifp->if_flags & IFF_UP) { - if ((ifp->if_flags & IFF_RUNNING)) { - if ((ifp->if_flags ^ adapter->if_flags) & - (IFF_PROMISC | IFF_ALLMULTI)) { - ixgbe_set_promisc(adapter); - } - } else - ixgbe_init_locked(adapter); - } else - if (ifp->if_flags & IFF_RUNNING) - ixgbe_stop(adapter); - adapter->if_flags = ifp->if_flags; - IXGBE_CORE_UNLOCK(adapter); - break; - case SIOCADDMULTI: - case SIOCDELMULTI: - IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); - if (ifp->if_flags & IFF_RUNNING) { - IXGBE_CORE_LOCK(adapter); - ixgbe_disable_intr(adapter); - ixgbe_set_multi(adapter); - ixgbe_enable_intr(adapter); - IXGBE_CORE_UNLOCK(adapter); - } - break; - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); - error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); - break; - case SIOCSIFCAP: - { - int mask = ifr->ifr_reqcap ^ ifp->if_capenable; - IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); - if (mask & IFCAP_HWCSUM) - ifp->if_capenable ^= IFCAP_HWCSUM; - if (mask & IFCAP_TSO4) - ifp->if_capenable ^= IFCAP_TSO4; - if (mask & IFCAP_TSO6) - ifp->if_capenable ^= IFCAP_TSO6; -#if 0 /* NET_LRO */ - if (mask & IFCAP_LRO) - ifp->if_capenable ^= IFCAP_LRO; -#endif - if (mask & IFCAP_VLAN_HWTAGGING) - ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; - if (mask & IFCAP_VLAN_HWFILTER) - ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; -#if 0 /* NET_TSO */ - if (mask & IFCAP_VLAN_HWTSO) - ifp->if_capenable ^= IFCAP_VLAN_HWTSO; -#endif - if (ifp->if_flags & IFF_RUNNING) { - IXGBE_CORE_LOCK(adapter); - ixgbe_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); - } -#if 0 - VLAN_CAPABILITIES(ifp); -#endif - break; - } - - default: - IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); - error = ether_ioctl(ifp, command, data); - break; - } - - return (error); -} - -/********************************************************************* - * 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 - -static void -ixgbe_init_locked(struct adapter *adapter) -{ - struct ifnet *ifp = adapter->ifp; - device_t dev = adapter->dev; - struct ixgbe_hw *hw = &adapter->hw; - u32 k, txdctl, mhadd, gpie; - u32 rxdctl, rxctrl; - - KKASSERT(lockstatus(&adapter->core_lock, curthread) != 0); - INIT_DEBUGOUT("ixgbe_init: begin"); - hw->adapter_stopped = FALSE; - ixgbe_stop_adapter(hw); - callout_stop(&adapter->timer); - - /* reprogram the RAR[0] in case user changed it. */ - ixgbe_set_rar(hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); - - /* Get the latest mac address, User can use a LAA */ - bcopy(IF_LLADDR(adapter->ifp), hw->mac.addr, - IXGBE_ETH_LENGTH_OF_ADDRESS); - ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1); - hw->addr_ctrl.rar_used_count = 1; - - /* Set the various hardware offload abilities */ - ifp->if_hwassist = 0; - if (ifp->if_capenable & IFCAP_TSO) - ifp->if_hwassist |= CSUM_TSO; - if (ifp->if_capenable & IFCAP_TXCSUM) { - ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); -#if 0 - if (hw->mac.type != ixgbe_mac_82598EB) - ifp->if_hwassist |= CSUM_SCTP; -#endif - } - - /* Prepare transmit descriptors and buffers */ - if (ixgbe_setup_transmit_structures(adapter)) { - device_printf(dev,"Could not setup transmit structures\n"); - ixgbe_stop(adapter); - return; - } - - ixgbe_init_hw(hw); - ixgbe_initialize_transmit_units(adapter); - - /* Setup Multicast table */ - ixgbe_set_multi(adapter); - - /* - ** Determine the correct mbuf pool - ** for doing jumbo/headersplit - */ -#if 0 /* XXX */ - if (adapter->max_frame_size <= 2048) - adapter->rx_mbuf_sz = MCLBYTES; - else if (adapter->max_frame_size <= 4096) - adapter->rx_mbuf_sz = MJUMPAGESIZE; - else if (adapter->max_frame_size <= 9216) - adapter->rx_mbuf_sz = MJUM9BYTES; - else - adapter->rx_mbuf_sz = MJUM16BYTES; -#else - adapter->rx_mbuf_sz = MCLBYTES; -#endif - - /* Prepare receive descriptors and buffers */ - if (ixgbe_setup_receive_structures(adapter)) { - device_printf(dev,"Could not setup receive structures\n"); - ixgbe_stop(adapter); - return; - } - - /* Configure RX settings */ - ixgbe_initialize_receive_units(adapter); - - gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE); - - /* Enable Fan Failure Interrupt */ - gpie |= IXGBE_SDP1_GPIEN; - - /* Add for Module detection */ - if (hw->mac.type == ixgbe_mac_82599EB) - gpie |= IXGBE_SDP2_GPIEN; - - /* Thermal Failure Detection */ - if (hw->mac.type == ixgbe_mac_X540) - gpie |= IXGBE_SDP0_GPIEN; - - if (adapter->msix > 1) { - /* Enable Enhanced MSIX mode */ - gpie |= IXGBE_GPIE_MSIX_MODE; - gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | - IXGBE_GPIE_OCD; - } - IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); - - /* Set MTU size */ - if (ifp->if_mtu > ETHERMTU) { - mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); - mhadd &= ~IXGBE_MHADD_MFS_MASK; - mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; - IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); - } - - /* Now enable all the queues */ - - for (int i = 0; i < adapter->num_queues; i++) { - txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i)); - txdctl |= IXGBE_TXDCTL_ENABLE; - /* Set WTHRESH to 8, burst writeback */ - txdctl |= (8 << 16); - /* - * When the internal queue falls below PTHRESH (32), - * start prefetching as long as there are at least - * HTHRESH (1) buffers ready. The values are taken - * from the Intel linux driver 3.8.21. - * Prefetching enables tx line rate even with 1 queue. - */ - txdctl |= (32 << 0) | (1 << 8); - IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), txdctl); - } - - for (int i = 0; i < adapter->num_queues; i++) { - rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); - if (hw->mac.type == ixgbe_mac_82598EB) { - /* - ** PTHRESH = 21 - ** HTHRESH = 4 - ** WTHRESH = 8 - */ - rxdctl &= ~0x3FFFFF; - rxdctl |= 0x080420; - } - rxdctl |= IXGBE_RXDCTL_ENABLE; - IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl); - for (k = 0; k < 10; k++) { - if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)) & - IXGBE_RXDCTL_ENABLE) - break; - else - msec_delay(1); - } - wmb(); -#ifdef DEV_NETMAP - /* - * In netmap mode, we must preserve the buffers made - * available to userspace before the if_init() - * (this is true by default on the TX side, because - * init makes all buffers available to userspace). - * - * netmap_reset() and the device specific routines - * (e.g. ixgbe_setup_receive_rings()) map these - * buffers at the end of the NIC ring, so here we - * must set the RDT (tail) register to make sure - * they are not overwritten. - * - * In this driver the NIC ring starts at RDH = 0, - * RDT points to the last slot available for reception (?), - * so RDT = num_rx_desc - 1 means the whole ring is available. - */ - if (ifp->if_capenable & IFCAP_NETMAP) { - struct netmap_adapter *na = NA(adapter->ifp); - struct netmap_kring *kring = &na->rx_rings[i]; - int t = na->num_rx_desc - 1 - kring->nr_hwavail; - - IXGBE_WRITE_REG(hw, IXGBE_RDT(i), t); - } else -#endif /* DEV_NETMAP */ - IXGBE_WRITE_REG(hw, IXGBE_RDT(i), adapter->num_rx_desc - 1); - } - - /* Set up VLAN support and filter */ - ixgbe_setup_vlan_hw_support(adapter); - - /* Enable Receive engine */ - rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); - if (hw->mac.type == ixgbe_mac_82598EB) - rxctrl |= IXGBE_RXCTRL_DMBYPS; - rxctrl |= IXGBE_RXCTRL_RXEN; - ixgbe_enable_rx_dma(hw, rxctrl); - - callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); - - /* Set up MSI/X routing */ - if (ixgbe_enable_msix) { - ixgbe_configure_ivars(adapter); - /* Set up auto-mask */ - if (hw->mac.type == ixgbe_mac_82598EB) - IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); - else { - IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); - IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); - } - } else { /* Simple settings for Legacy/MSI */ - ixgbe_set_ivar(adapter, 0, 0, 0); - ixgbe_set_ivar(adapter, 0, 0, 1); - IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); - } - -#ifdef IXGBE_FDIR - /* Init Flow director */ - if (hw->mac.type != ixgbe_mac_82598EB) { - u32 hdrm = 32 << fdir_pballoc; - - hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); - ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); - } -#endif - - /* - ** Check on any SFP devices that - ** need to be kick-started - */ - if (hw->phy.type == ixgbe_phy_none) { - int err = hw->phy.ops.identify(hw); - if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - device_printf(dev, - "Unsupported SFP+ module type was detected.\n"); - return; - } - } - - /* Set moderation on the Link interrupt */ - ixgbe_set_eitr(adapter, adapter->linkvec, IXGBE_LINK_ITR); - - /* Config/Enable Link */ - ixgbe_config_link(adapter); - - /* Hardware Packet Buffer & Flow Control setup */ - { - u32 rxpb, frame, size, tmp; - - frame = adapter->max_frame_size; - - /* Calculate High Water */ - if (hw->mac.type == ixgbe_mac_X540) - tmp = IXGBE_DV_X540(frame, frame); - else - tmp = IXGBE_DV(frame, frame); - size = IXGBE_BT2KB(tmp); - rxpb = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0)) >> 10; - hw->fc.high_water[0] = rxpb - size; - - /* Now calculate Low Water */ - if (hw->mac.type == ixgbe_mac_X540) - tmp = IXGBE_LOW_DV_X540(frame); - else - tmp = IXGBE_LOW_DV(frame); - hw->fc.low_water[0] = IXGBE_BT2KB(tmp); - - adapter->fc = hw->fc.requested_mode = ixgbe_fc_full; - hw->fc.pause_time = IXGBE_FC_PAUSE; - hw->fc.send_xon = TRUE; - } - /* Initialize the FC settings */ - ixgbe_start_hw(hw); - - /* And now turn on interrupts */ - ixgbe_enable_intr(adapter); - - /* Now inform the stack we're ready */ - ifp->if_flags |= IFF_RUNNING; - ifq_clr_oactive(&ifp->if_snd); - - return; -} - -static void -ixgbe_init(void *arg) -{ - struct adapter *adapter = arg; - - IXGBE_CORE_LOCK(adapter); - ixgbe_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); - return; -} - - -/* -** -** MSIX Interrupt Handlers and Tasklets -** -*/ - -static inline void -ixgbe_enable_queue(struct adapter *adapter, u32 vector) -{ - struct ixgbe_hw *hw = &adapter->hw; - u64 queue = (u64)(1 << vector); - u32 mask; - - if (hw->mac.type == ixgbe_mac_82598EB) { - mask = (IXGBE_EIMS_RTX_QUEUE & queue); - IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); - } else { - mask = (queue & 0xFFFFFFFF); - if (mask) - IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask); - mask = (queue >> 32); - if (mask) - IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(1), mask); - } -} - -static inline void -ixgbe_disable_queue(struct adapter *adapter, u32 vector) -{ - struct ixgbe_hw *hw = &adapter->hw; - u64 queue = (u64)(1 << vector); - u32 mask; - - if (hw->mac.type == ixgbe_mac_82598EB) { - mask = (IXGBE_EIMS_RTX_QUEUE & queue); - IXGBE_WRITE_REG(hw, IXGBE_EIMC, mask); - } else { - mask = (queue & 0xFFFFFFFF); - if (mask) - IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); - mask = (queue >> 32); - if (mask) - IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); - } -} - -static inline void -ixgbe_rearm_queues(struct adapter *adapter, u64 queues) -{ - u32 mask; - - if (adapter->hw.mac.type == ixgbe_mac_82598EB) { - mask = (IXGBE_EIMS_RTX_QUEUE & queues); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); - } else { - mask = (queues & 0xFFFFFFFF); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); - mask = (queues >> 32); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); - } -} - -/********************************************************************* - * - * Legacy Interrupt Service routine - * - **********************************************************************/ - -static void -ixgbe_legacy_irq(void *arg) -{ - struct ix_queue *que = arg; - struct adapter *adapter = que->adapter; - struct ixgbe_hw *hw = &adapter->hw; - struct tx_ring *txr = adapter->tx_rings; - u32 reg_eicr; - - - reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); - - ++que->irqs; - if (reg_eicr == 0) { - ixgbe_enable_intr(adapter); - return; - } - - ixgbe_rxeof(que, adapter->rx_process_limit); - - IXGBE_TX_LOCK(txr); - ixgbe_txeof(txr); - if (!ifq_is_empty(&adapter->ifp->if_snd)) - ixgbe_start_locked(txr, adapter->ifp); - IXGBE_TX_UNLOCK(txr); - - /* Check for fan failure */ - if ((hw->phy.media_type == ixgbe_media_type_copper) && - (reg_eicr & IXGBE_EICR_GPI_SDP1)) { - device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " - "REPLACE IMMEDIATELY!!\n"); - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1); - } - - /* Link status change */ - if (reg_eicr & IXGBE_EICR_LSC) { - ixgbe_check_link(&adapter->hw, - &adapter->link_speed, &adapter->link_up, 0); - ixgbe_update_link_status(adapter); - } - - ixgbe_enable_intr(adapter); -} - - -/********************************************************************* - * - * MSIX Queue Interrupt Service routine - * - **********************************************************************/ -void -ixgbe_msix_que(void *arg) -{ - struct ix_queue *que = arg; - struct adapter *adapter = que->adapter; - struct tx_ring *txr = que->txr; - - ixgbe_disable_queue(adapter, que->msix); - ++que->irqs; - - ixgbe_rxeof(que, adapter->rx_process_limit); - - IXGBE_TX_LOCK(txr); - ixgbe_txeof(txr); - if (!ifq_is_empty(&adapter->ifp->if_snd)) - ixgbe_start_locked(txr, adapter->ifp); - IXGBE_TX_UNLOCK(txr); - - /* Reenable this interrupt */ - ixgbe_enable_queue(adapter, que->msix); -} - - -static void -ixgbe_msix_link(void *arg) -{ - struct adapter *adapter = arg; - struct ixgbe_hw *hw = &adapter->hw; - u32 reg_eicr; - - ++adapter->link_irq; - - /* First get the cause */ - reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); - /* Clear interrupt with write */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); - - /* Link status change */ - if (reg_eicr & IXGBE_EICR_LSC) { - ixgbe_check_link(&adapter->hw, - &adapter->link_speed, &adapter->link_up, 0); - ixgbe_update_link_status(adapter); - } - - if (adapter->hw.mac.type != ixgbe_mac_82598EB) { -#ifdef IXGBE_FDIR - if (reg_eicr & IXGBE_EICR_FLOW_DIR) { - /* This is probably overkill :) */ - if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) - return; - /* Disable the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR); - taskqueue_enqueue(adapter->tq, &adapter->fdir_task); - } else -#endif - if (reg_eicr & IXGBE_EICR_ECC) { - device_printf(adapter->dev, "\nCRITICAL: ECC ERROR!! " - "Please Reboot!!\n"); - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); - } else - - if (reg_eicr & IXGBE_EICR_GPI_SDP1) { - /* Clear the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); - taskqueue_enqueue(adapter->tq, &adapter->msf_task); - } else if (reg_eicr & IXGBE_EICR_GPI_SDP2) { - /* Clear the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); - taskqueue_enqueue(adapter->tq, &adapter->mod_task); - } - } - - /* Check for fan failure */ - if ((hw->device_id == IXGBE_DEV_ID_82598AT) && - (reg_eicr & IXGBE_EICR_GPI_SDP1)) { - device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " - "REPLACE IMMEDIATELY!!\n"); - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); - } - - /* Check for over temp condition */ - if ((hw->mac.type == ixgbe_mac_X540) && - (reg_eicr & IXGBE_EICR_GPI_SDP0)) { - device_printf(adapter->dev, "\nCRITICAL: OVER TEMP!! " - "PHY IS SHUT DOWN!!\n"); - device_printf(adapter->dev, "System shutdown required\n"); - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0); - } - - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); - return; -} - -/********************************************************************* - * - * Media Ioctl callback - * - * This routine is called whenever the user queries the status of - * the interface using ifconfig. - * - **********************************************************************/ -static void -ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) -{ - struct adapter *adapter = ifp->if_softc; - - ASSERT_IFNET_SERIALIZED_ALL(ifp); - - INIT_DEBUGOUT("ixgbe_media_status: begin"); - ixgbe_update_link_status(adapter); - - ifmr->ifm_status = IFM_AVALID; - ifmr->ifm_active = IFM_ETHER; - - if (!adapter->link_active) - return; - - ifmr->ifm_status |= IFM_ACTIVE; - - switch (adapter->link_speed) { - case IXGBE_LINK_SPEED_100_FULL: - ifmr->ifm_active |= IFM_100_TX | IFM_FDX; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - ifmr->ifm_active |= IFM_1000_T | IFM_FDX; - break; - case IXGBE_LINK_SPEED_10GB_FULL: - ifmr->ifm_active |= adapter->optics | IFM_FDX; - break; - } - - return; -} - -/********************************************************************* - * - * Media Ioctl callback - * - * This routine is called when the user changes speed/duplex using - * media/mediopt option with ifconfig. - * - **********************************************************************/ -static int -ixgbe_media_change(struct ifnet * ifp) -{ - struct adapter *adapter = ifp->if_softc; - struct ifmedia *ifm = &adapter->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: - adapter->hw.phy.autoneg_advertised = - IXGBE_LINK_SPEED_100_FULL | - IXGBE_LINK_SPEED_1GB_FULL | - IXGBE_LINK_SPEED_10GB_FULL; - break; - default: - device_printf(adapter->dev, "Only auto media type\n"); - return (EINVAL); - } - - return (0); -} - -/********************************************************************* - * - * This routine maps the mbufs to tx descriptors, allowing the - * TX engine to transmit the packets. - * - return 0 on success, positive on failure - * - **********************************************************************/ - -static int -ixgbe_xmit(struct tx_ring *txr, struct mbuf **m_headp) -{ - struct adapter *adapter = txr->adapter; - u32 olinfo_status = 0, cmd_type_len; - u32 paylen = 0; - int i, j, error, nsegs, maxsegs; - int first, last = 0; - struct mbuf *m_head; - bus_dma_segment_t segs[adapter->num_segs]; - bus_dmamap_t map; - struct ixgbe_tx_buf *txbuf; - union ixgbe_adv_tx_desc *txd = NULL; - - m_head = *m_headp; - - if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { - error = ixgbe_tso_pullup(txr, m_headp); - if (error) - return error; - m_head = *m_headp; - } - - /* Basic descriptor defines */ - cmd_type_len = (IXGBE_ADVTXD_DTYP_DATA | - IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT); - - if (m_head->m_flags & M_VLANTAG) - cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE; - - /* - * 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_desc; - txbuf = &txr->tx_buffers[first]; - map = txbuf->map; - - /* - * Map the packet for DMA. - */ - maxsegs = txr->tx_avail - IXGBE_TX_RESERVED; - if (maxsegs > adapter->num_segs) - maxsegs = adapter->num_segs; - - error = bus_dmamap_load_mbuf_defrag(txr->txtag, map, m_headp, - segs, maxsegs, &nsegs, BUS_DMA_NOWAIT); - if (error) { - if (error == ENOBUFS) - adapter->mbuf_defrag_failed++; - else - adapter->no_tx_dma_setup++; - - m_freem(*m_headp); - *m_headp = NULL; - return (error); - } - - /* Make certain there are enough descriptors */ - if (nsegs > txr->tx_avail - 2) { - txr->no_desc_avail++; - error = ENOBUFS; - goto xmit_fail; - } - m_head = *m_headp; - - /* - ** Set up the appropriate offload context - ** this becomes the first descriptor of - ** a packet. - */ - if (m_head->m_pkthdr.csum_flags & CSUM_TSO) { - if (ixgbe_tso_setup(txr, m_head, &paylen, &olinfo_status)) { - cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE; - olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; - olinfo_status |= paylen << IXGBE_ADVTXD_PAYLEN_SHIFT; - ++adapter->tso_tx; - } else - return (ENXIO); - } else if (ixgbe_tx_ctx_setup(txr, m_head)) - olinfo_status |= IXGBE_TXD_POPTS_TXSM << 8; - -#ifdef IXGBE_IEEE1588 - /* This is changing soon to an mtag detection */ - if (we detect this mbuf has a TSTAMP mtag) - cmd_type_len |= IXGBE_ADVTXD_MAC_TSTAMP; -#endif - -#ifdef IXGBE_FDIR - /* Do the flow director magic */ - if ((txr->atr_sample) && (!adapter->fdir_reinit)) { - ++txr->atr_count; - if (txr->atr_count >= atr_sample_rate) { - ixgbe_atr(txr, m_head); - txr->atr_count = 0; - } - } -#endif - /* Record payload length */ - if (paylen == 0) - olinfo_status |= m_head->m_pkthdr.len << - IXGBE_ADVTXD_PAYLEN_SHIFT; - - i = txr->next_avail_desc; - for (j = 0; j < nsegs; j++) { - bus_size_t seglen; - bus_addr_t segaddr; - - txbuf = &txr->tx_buffers[i]; - txd = &txr->tx_base[i]; - seglen = segs[j].ds_len; - segaddr = htole64(segs[j].ds_addr); - - txd->read.buffer_addr = segaddr; - txd->read.cmd_type_len = htole32(txr->txd_cmd | - cmd_type_len |seglen); - txd->read.olinfo_status = htole32(olinfo_status); - last = i; /* descriptor that will get completion IRQ */ - - if (++i == adapter->num_tx_desc) - i = 0; - - txbuf->m_head = NULL; - txbuf->eop_index = -1; - } - - txd->read.cmd_type_len |= - htole32(IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS); - txr->tx_avail -= nsegs; - txr->next_avail_desc = i; - - txbuf->m_head = m_head; - /* Swap the dma map between the first and last descriptor */ - txr->tx_buffers[first].map = txbuf->map; - txbuf->map = map; - bus_dmamap_sync(txr->txtag, map, BUS_DMASYNC_PREWRITE); - - /* Set the index of the descriptor that will be marked done */ - txbuf = &txr->tx_buffers[first]; - txbuf->eop_index = last; - - bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - /* - * Advance the Transmit Descriptor Tail (Tdt), this tells the - * hardware that this frame is available to transmit. - */ - ++txr->total_packets; - IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(txr->me), i); - - return (0); - -xmit_fail: - bus_dmamap_unload(txr->txtag, txbuf->map); - return (error); - -} - -static void -ixgbe_set_promisc(struct adapter *adapter) -{ - u_int32_t reg_rctl; - struct ifnet *ifp = adapter->ifp; - - reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); - reg_rctl &= (~IXGBE_FCTRL_UPE); - reg_rctl &= (~IXGBE_FCTRL_MPE); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); - - if (ifp->if_flags & IFF_PROMISC) { - reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); - IXGBE_WRITE_REG(&adapter->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(&adapter->hw, IXGBE_FCTRL, reg_rctl); - } - return; -} - - -/********************************************************************* - * Multicast Update - * - * This routine is called whenever multicast address list is updated. - * - **********************************************************************/ -#define IXGBE_RAR_ENTRIES 16 - -static void -ixgbe_set_multi(struct adapter *adapter) -{ - u32 fctrl; - u8 *mta; - u8 *update_ptr; - struct ifmultiaddr *ifma; - int mcnt = 0; - struct ifnet *ifp = adapter->ifp; - - IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); - - mta = adapter->mta; - bzero(mta, sizeof(u8) * IXGBE_ETH_LENGTH_OF_ADDRESS * - MAX_NUM_MULTICAST_ADDRESSES); - - fctrl = IXGBE_READ_REG(&adapter->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(&adapter->hw, IXGBE_FCTRL, fctrl); - - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - if (ifma->ifma_addr->sa_family != AF_LINK) - continue; - bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), - &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS], - IXGBE_ETH_LENGTH_OF_ADDRESS); - mcnt++; - } - - update_ptr = mta; - ixgbe_update_mc_addr_list(&adapter->hw, - update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); - - 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. - */ -static 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 check. - * - **********************************************************************/ - -static void -ixgbe_local_timer(void *arg) -{ - struct adapter *adapter = arg; - device_t dev = adapter->dev; - struct ifnet *ifp = adapter->ifp; - struct ix_queue *que = adapter->queues; - struct tx_ring *txr = adapter->tx_rings; - int hung, busy, paused; - - IXGBE_CORE_LOCK(adapter); - hung = busy = paused = 0; - - /* Check for pluggable optics */ - if (adapter->sfp_probe) - if (!ixgbe_sfp_probe(adapter)) - goto out; /* Nothing to do */ - - ixgbe_update_link_status(adapter); - ixgbe_update_stats_counters(adapter); - - /* - * If the interface has been paused - * then don't do the watchdog check - */ - if (IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF) - paused = 1; - - /* - ** Check the TX queues status - ** - central locked handling of OACTIVE - ** - watchdog only if all queues show hung - */ - for (int i = 0; i < adapter->num_queues; i++, que++, txr++) { - if ((txr->queue_status & IXGBE_QUEUE_HUNG) && - (paused == 0)) - ++hung; - if (txr->queue_status & IXGBE_QUEUE_DEPLETED) - ++busy; - } - /* Only truely watchdog if all queues show hung */ - if (hung == adapter->num_queues) - goto watchdog; - /* Only turn off the stack flow when ALL are depleted */ - if (busy == adapter->num_queues) - ifq_set_oactive(&ifp->if_snd); - else if (ifq_is_oactive(&ifp->if_snd) && (busy < adapter->num_queues)) - ifq_clr_oactive(&ifp->if_snd); - -out: - ixgbe_rearm_queues(adapter, adapter->que_mask); - callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); - IXGBE_CORE_UNLOCK(adapter); - return; - -watchdog: - device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); - device_printf(dev,"Queue(%d) tdh = %d, hw tdt = %d\n", txr->me, - IXGBE_READ_REG(&adapter->hw, IXGBE_TDH(txr->me)), - IXGBE_READ_REG(&adapter->hw, IXGBE_TDT(txr->me))); - device_printf(dev,"TX(%d) desc avail = %d," - "Next TX to Clean = %d\n", - txr->me, txr->tx_avail, txr->next_to_clean); - adapter->ifp->if_flags &= ~IFF_RUNNING; - adapter->watchdog_events++; - ixgbe_init_locked(adapter); - - IXGBE_CORE_UNLOCK(adapter); -} - -/* -** Note: this routine updates the OS on the link state -** the real check of the hardware only happens with -** a link interrupt. -*/ -static void -ixgbe_update_link_status(struct adapter *adapter) -{ - struct ifnet *ifp = adapter->ifp; - struct tx_ring *txr = adapter->tx_rings; - device_t dev = adapter->dev; - - - if (adapter->link_up){ - if (adapter->link_active == FALSE) { - if (bootverbose) - device_printf(dev,"Link is up %d Gbps %s \n", - ((adapter->link_speed == 128)? 10:1), - "Full Duplex"); - adapter->link_active = TRUE; - /* Update any Flow Control changes */ - ixgbe_fc_enable(&adapter->hw); - ifp->if_link_state = LINK_STATE_UP; - if_link_state_change(ifp); - } - } else { /* Link down */ - if (adapter->link_active == TRUE) { - if (bootverbose) - device_printf(dev,"Link is Down\n"); - ifp->if_link_state = LINK_STATE_DOWN; - if_link_state_change(ifp); - adapter->link_active = FALSE; - for (int i = 0; i < adapter->num_queues; - i++, txr++) - txr->queue_status = IXGBE_QUEUE_IDLE; - } - } - - return; -} - - -/********************************************************************* - * - * This routine disables all traffic on the adapter by issuing a - * global reset on the MAC and deallocates TX/RX buffers. - * - **********************************************************************/ - -static void -ixgbe_stop(void *arg) -{ - struct ifnet *ifp; - struct adapter *adapter = arg; - struct ixgbe_hw *hw = &adapter->hw; - ifp = adapter->ifp; - - KKASSERT(lockstatus(&adapter->core_lock, curthread) != 0); - - INIT_DEBUGOUT("ixgbe_stop: begin\n"); - ixgbe_disable_intr(adapter); - callout_stop(&adapter->timer); - - /* Let the stack know...*/ - ifp->if_flags &= ~IFF_RUNNING; - ifq_clr_oactive(&ifp->if_snd); - - ixgbe_reset_hw(hw); - hw->adapter_stopped = FALSE; - ixgbe_stop_adapter(hw); - /* Turn off the laser */ - if (hw->phy.multispeed_fiber) - ixgbe_disable_tx_laser(hw); - - /* reprogram the RAR[0] in case user changed it. */ - ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); - - return; -} - - -/********************************************************************* - * - * Determine hardware revision. - * - **********************************************************************/ -static void -ixgbe_identify_hardware(struct adapter *adapter) -{ - device_t dev = adapter->dev; - struct ixgbe_hw *hw = &adapter->hw; - - /* Save off the information about this board */ - hw->vendor_id = pci_get_vendor(dev); - hw->device_id = pci_get_device(dev); - hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); - hw->subsystem_vendor_id = - pci_read_config(dev, PCIR_SUBVEND_0, 2); - hw->subsystem_device_id = - pci_read_config(dev, PCIR_SUBDEV_0, 2); - - /* We need this here to set the num_segs below */ - ixgbe_set_mac_type(hw); - - /* Pick up the 82599 and VF settings */ - if (hw->mac.type != ixgbe_mac_82598EB) { - hw->phy.smart_speed = ixgbe_smart_speed; - adapter->num_segs = IXGBE_82599_SCATTER; - } else - adapter->num_segs = IXGBE_82598_SCATTER; - - return; -} - -/********************************************************************* - * - * Determine optic type - * - **********************************************************************/ -static void -ixgbe_setup_optics(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - int layer; - - layer = ixgbe_get_supported_physical_layer(hw); - - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) { - adapter->optics = IFM_10G_T; - return; - } - - if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) { - adapter->optics = IFM_1000_T; - return; - } - - if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_LR | - IXGBE_PHYSICAL_LAYER_10GBASE_LRM)) { - adapter->optics = IFM_10G_LR; - return; - } - - if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { - adapter->optics = IFM_10G_SR; - return; - } - - if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU) { - adapter->optics = IFM_10G_TWINAX; - return; - } - - if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | - IXGBE_PHYSICAL_LAYER_10GBASE_CX4)) { - adapter->optics = IFM_10G_CX4; - return; - } - - /* If we get here just set the default */ - adapter->optics = IFM_ETHER | IFM_AUTO; - return; -} - -/********************************************************************* - * - * Setup the Legacy or MSI Interrupt handler - * - **********************************************************************/ -static int -ixgbe_allocate_legacy(struct adapter *adapter) -{ - device_t dev = adapter->dev; - struct ix_queue *que = adapter->queues; - int error, rid = 0; - unsigned int intr_flags; - - /* MSI RID at 1 */ - if (adapter->msix == 1) - rid = 1; - - /* Try allocating a MSI interrupt first */ - adapter->intr_type = pci_alloc_1intr(dev, ixgbe_msi_enable, - &rid, &intr_flags); - - /* We allocate a single interrupt resource */ - adapter->res = bus_alloc_resource_any(dev, - SYS_RES_IRQ, &rid, intr_flags); - if (adapter->res == NULL) { - device_printf(dev, "Unable to allocate bus resource: " - "interrupt\n"); - return (ENXIO); - } - - /* Tasklets for Link, SFP and Multispeed Fiber */ - TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); - TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); -#ifdef IXGBE_FDIR - TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); -#endif - - if ((error = bus_setup_intr(dev, adapter->res, INTR_MPSAFE, - ixgbe_legacy_irq, que, &adapter->tag, &adapter->serializer)) != 0) { - device_printf(dev, "Failed to register fast interrupt " - "handler: %d\n", error); - taskqueue_free(adapter->tq); - adapter->tq = NULL; - return (error); - } - /* For simplicity in the handlers */ - adapter->que_mask = IXGBE_EIMS_ENABLE_MASK; - - return (0); -} - - -/********************************************************************* - * - * Setup MSIX Interrupt resources and handlers - * - **********************************************************************/ -static int -ixgbe_allocate_msix(struct adapter *adapter) -{ - device_t dev = adapter->dev; - struct ix_queue *que = adapter->queues; - int error, rid, vector = 0; - char desc[16]; - - error = pci_setup_msix(dev); - if (error) { - device_printf(dev, "MSI-X setup failed\n"); - return (error); - } - - for (int i = 0; i < adapter->num_queues; i++, vector++, que++) { - rid = vector + 1; - - /* - ** Bind the msix vector, and thus the - ** ring to the corresponding cpu. - */ - error = pci_alloc_msix_vector(dev, vector, &rid, i); - if (error) { - device_printf(dev, "pci_alloc_msix_vector failed\n"); - return (error); - } - - que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (que->res == NULL) { - device_printf(dev,"Unable to allocate" - " bus resource: que interrupt [%d]\n", vector); - return (ENXIO); - } - /* Set the handler function */ - ksnprintf(desc, sizeof(desc), "%s que %d", - device_get_nameunit(dev), i); - error = bus_setup_intr_descr(dev, que->res, INTR_MPSAFE, - ixgbe_msix_que, que, &que->tag, &que->serializer, desc); - if (error) { - que->res = NULL; - device_printf(dev, "Failed to register QUE handler"); - return (error); - } - que->msix = vector; - adapter->que_mask |= (u64)(1 << que->msix); - } - - /* and Link, bind vector to cpu #0 */ - rid = vector + 1; - error = pci_alloc_msix_vector(dev, vector, &rid, 0); - if (error) { - device_printf(dev, "pci_alloc_msix_vector failed\n"); - return (error); - } - adapter->res = bus_alloc_resource_any(dev, - SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); - if (!adapter->res) { - device_printf(dev,"Unable to allocate" - " bus resource: Link interrupt [%d]\n", rid); - return (ENXIO); - } - /* Set the link handler function */ - error = bus_setup_intr_descr(dev, adapter->res, INTR_MPSAFE, - ixgbe_msix_link, adapter, &adapter->tag, &adapter->serializer, - "link"); - if (error) { - adapter->res = NULL; - device_printf(dev, "Failed to register LINK handler"); - return (error); - } - pci_enable_msix(dev); - - adapter->linkvec = vector; - /* Tasklets for Link, SFP and Multispeed Fiber */ - TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); - TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); -#ifdef IXGBE_FDIR - TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); -#endif - - return (0); -} - -/* - * Setup Either MSI/X or MSI - */ -static int -ixgbe_setup_msix(struct adapter *adapter) -{ - device_t dev = adapter->dev; - int rid, want, queues, msgs; - - /* Override by tuneable */ - if (ixgbe_enable_msix == 0) - goto msi; - - /* First try MSI/X */ - rid = PCIR_BAR(MSIX_82598_BAR); - adapter->msix_mem = bus_alloc_resource_any(dev, - SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (!adapter->msix_mem) { - rid += 4; /* 82599 maps in higher BAR */ - adapter->msix_mem = bus_alloc_resource_any(dev, - SYS_RES_MEMORY, &rid, RF_ACTIVE); - } - if (!adapter->msix_mem) { - /* May not be enabled */ - device_printf(adapter->dev, - "Unable to map MSIX table \n"); - goto msi; - } - - msgs = pci_msix_count(dev); - if (msgs == 0) { /* system has msix disabled */ - bus_release_resource(dev, SYS_RES_MEMORY, - rid, adapter->msix_mem); - adapter->msix_mem = NULL; - goto msi; - } - - /* Figure out a reasonable auto config value */ - queues = (ncpus > (msgs-1)) ? (msgs-1) : ncpus; - - if (ixgbe_num_queues != 0) - queues = ixgbe_num_queues; - /* Set max queues to 8 when autoconfiguring */ - else if ((ixgbe_num_queues == 0) && (queues > 8)) - queues = 8; - - /* - ** Want one vector (RX/TX pair) per queue - ** plus an additional for Link. - */ - want = queues + 1; - if (msgs >= want) - msgs = want; - else { - device_printf(adapter->dev, - "MSIX Configuration Problem, " - "%d vectors but %d queues wanted!\n", - msgs, want); - return (0); /* Will go to Legacy setup */ - } - if (msgs) { - device_printf(adapter->dev, - "Using MSIX interrupts with %d vectors\n", msgs); - adapter->num_queues = queues; - return (msgs); - } -msi: - msgs = pci_msi_count(dev); - return (msgs); -} - - -static int -ixgbe_allocate_pci_resources(struct adapter *adapter) -{ - int rid; - device_t dev = adapter->dev; - - rid = PCIR_BAR(0); - adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &rid, RF_ACTIVE); - - if (!(adapter->pci_mem)) { - device_printf(dev,"Unable to allocate bus resource: memory\n"); - return (ENXIO); - } - - adapter->osdep.mem_bus_space_tag = - rman_get_bustag(adapter->pci_mem); - adapter->osdep.mem_bus_space_handle = - rman_get_bushandle(adapter->pci_mem); - adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; - - /* Legacy defaults */ - adapter->num_queues = 1; - adapter->hw.back = &adapter->osdep; - - /* - ** Now setup MSI or MSI/X, should - ** return us the number of supported - ** vectors. (Will be 1 for MSI) - */ - adapter->msix = ixgbe_setup_msix(adapter); - return (0); -} - -static void -ixgbe_free_pci_resources(struct adapter * adapter) -{ - struct ix_queue *que = adapter->queues; - device_t dev = adapter->dev; - int rid, memrid; - - if (adapter->hw.mac.type == ixgbe_mac_82598EB) - memrid = PCIR_BAR(MSIX_82598_BAR); - else - memrid = PCIR_BAR(MSIX_82599_BAR); - - /* - ** There is a slight possibility of a failure mode - ** in attach that will result in entering this function - ** before interrupt resources have been initialized, and - ** in that case we do not want to execute the loops below - ** We can detect this reliably by the state of the adapter - ** res pointer. - */ - if (adapter->res == NULL) - goto mem; - - /* - ** Release all msix queue resources: - */ - for (int i = 0; i < adapter->num_queues; i++, que++) { - rid = que->msix + 1; - if (que->tag != NULL) { - bus_teardown_intr(dev, que->res, que->tag); - que->tag = NULL; - } - if (que->res != NULL) - bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); - } - - - /* Clean the Legacy or Link interrupt last */ - if (adapter->linkvec) /* we are doing MSIX */ - rid = adapter->linkvec + 1; - else - (adapter->msix != 0) ? (rid = 1):(rid = 0); - - if (adapter->tag != NULL) { - bus_teardown_intr(dev, adapter->res, adapter->tag); - adapter->tag = NULL; - } - if (adapter->res != NULL) - bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); - if (adapter->intr_type == PCI_INTR_TYPE_MSI) - pci_release_msi(adapter->dev); - -mem: - if (adapter->msix) - pci_release_msi(dev); - - if (adapter->msix_mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - memrid, adapter->msix_mem); - - if (adapter->pci_mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - PCIR_BAR(0), adapter->pci_mem); - - return; -} - -/********************************************************************* - * - * Setup networking device structure and register an interface. - * - **********************************************************************/ -static int -ixgbe_setup_interface(device_t dev, struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - struct ifnet *ifp; - - INIT_DEBUGOUT("ixgbe_setup_interface: begin"); - - ifp = adapter->ifp = if_alloc(IFT_ETHER); - if (ifp == NULL) { - device_printf(dev, "can not allocate ifnet structure\n"); - return (-1); - } - if_initname(ifp, device_get_name(dev), device_get_unit(dev)); - ifp->if_baudrate = 1000000000; - ifp->if_init = ixgbe_init; - ifp->if_softc = adapter; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = ixgbe_ioctl; - ifp->if_start = ixgbe_start; -#if 0 /* __FreeBSD_version >= 800000 */ - ifp->if_transmit = ixgbe_mq_start; - ifp->if_qflush = ixgbe_qflush; -#endif - ifq_set_maxlen(&ifp->if_snd, adapter->num_tx_desc - 2); - - ether_ifattach(ifp, adapter->hw.mac.addr, NULL); - - adapter->max_frame_size = - ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; - - /* - * Tell the upper layer(s) we support long frames. - */ - ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); - - ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO | IFCAP_VLAN_HWCSUM; - ifp->if_capabilities |= IFCAP_JUMBO_MTU; - ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING -#if 0 /* NET_TSO */ - | IFCAP_VLAN_HWTSO -#endif - | IFCAP_VLAN_MTU; - ifp->if_capenable = ifp->if_capabilities; - - /* Don't enable LRO by default */ -#if 0 /* NET_LRO */ - ifp->if_capabilities |= IFCAP_LRO; -#endif - - /* - ** Don't turn this on by default, if vlans are - ** created on another pseudo device (eg. lagg) - ** then vlan events are not passed thru, breaking - ** operation, but with HW FILTER off it works. If - ** using vlans directly on the ixgbe driver you can - ** enable this and get full hardware tag filtering. - */ - ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; - - /* - * Specify the media types supported by this adapter and register - * callbacks to update media and link information - */ - ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, - ixgbe_media_status); - ifmedia_add(&adapter->media, IFM_ETHER | adapter->optics, 0, NULL); - ifmedia_set(&adapter->media, IFM_ETHER | adapter->optics); - if (hw->device_id == IXGBE_DEV_ID_82598AT) { - ifmedia_add(&adapter->media, - IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); - ifmedia_add(&adapter->media, - IFM_ETHER | IFM_1000_T, 0, NULL); - } - ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); - ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); - - return (0); -} - -static void -ixgbe_config_link(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - u32 autoneg, err = 0; - bool sfp, negotiate; - - sfp = ixgbe_is_sfp(hw); - - if (sfp) { - if (hw->phy.multispeed_fiber) { - hw->mac.ops.setup_sfp(hw); - ixgbe_enable_tx_laser(hw); - taskqueue_enqueue(adapter->tq, &adapter->msf_task); - } else - taskqueue_enqueue(adapter->tq, &adapter->mod_task); - } else { - if (hw->mac.ops.check_link) - err = ixgbe_check_link(hw, &autoneg, - &adapter->link_up, FALSE); - if (err) - goto out; - autoneg = hw->phy.autoneg_advertised; - if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) - err = hw->mac.ops.get_link_capabilities(hw, - &autoneg, &negotiate); - if (err) - goto out; - if (hw->mac.ops.setup_link) - err = hw->mac.ops.setup_link(hw, autoneg, - negotiate, adapter->link_up); - } -out: - return; -} - -/******************************************************************** - * Manage DMA'able memory. - *******************************************************************/ -static void -ixgbe_dmamap_cb(void *arg, bus_dma_segment_t * segs, int nseg, int error) -{ - if (error) - return; - *(bus_addr_t *) arg = segs->ds_addr; - return; -} - -static int -ixgbe_dma_malloc(struct adapter *adapter, bus_size_t size, - struct ixgbe_dma_alloc *dma, int mapflags) -{ - device_t dev = adapter->dev; - int r; - - r = bus_dma_tag_create(NULL, /* parent */ - DBA_ALIGN, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - size, /* maxsize */ - 1, /* nsegments */ - size, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ - &dma->dma_tag); - if (r != 0) { - device_printf(dev,"ixgbe_dma_malloc: bus_dma_tag_create failed; " - "error %u\n", r); - goto fail_0; - } - r = bus_dmamem_alloc(dma->dma_tag, (void **)&dma->dma_vaddr, - BUS_DMA_NOWAIT, &dma->dma_map); - if (r != 0) { - device_printf(dev,"ixgbe_dma_malloc: bus_dmamem_alloc failed; " - "error %u\n", r); - goto fail_1; - } - r = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, - size, - ixgbe_dmamap_cb, - &dma->dma_paddr, - mapflags | BUS_DMA_NOWAIT); - if (r != 0) { - device_printf(dev,"ixgbe_dma_malloc: bus_dmamap_load failed; " - "error %u\n", r); - goto fail_2; - } - dma->dma_size = size; - return (0); -fail_2: - bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); -fail_1: - bus_dma_tag_destroy(dma->dma_tag); -fail_0: - dma->dma_map = NULL; - dma->dma_tag = NULL; - return (r); -} - -static void -ixgbe_dma_free(struct adapter *adapter, struct ixgbe_dma_alloc *dma) -{ - bus_dmamap_sync(dma->dma_tag, dma->dma_map, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(dma->dma_tag, dma->dma_map); - bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); - bus_dma_tag_destroy(dma->dma_tag); -} - - -/********************************************************************* - * - * Allocate memory for the transmit and receive rings, and then - * the descriptors associated with each, called only once at attach. - * - **********************************************************************/ -static int -ixgbe_allocate_queues(struct adapter *adapter) -{ - device_t dev = adapter->dev; - struct ix_queue *que; - struct tx_ring *txr; - struct rx_ring *rxr; - int rsize, tsize, error = IXGBE_SUCCESS; - int txconf = 0, rxconf = 0; - - /* First allocate the top level queue structs */ - if (!(adapter->queues = - (struct ix_queue *) kmalloc(sizeof(struct ix_queue) * - adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { - device_printf(dev, "Unable to allocate queue memory\n"); - error = ENOMEM; - goto fail; - } - - /* First allocate the TX ring struct memory */ - if (!(adapter->tx_rings = - (struct tx_ring *) kmalloc(sizeof(struct tx_ring) * - adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { - device_printf(dev, "Unable to allocate TX ring memory\n"); - error = ENOMEM; - goto tx_fail; - } - - /* Next allocate the RX */ - if (!(adapter->rx_rings = - (struct rx_ring *) kmalloc(sizeof(struct rx_ring) * - adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { - device_printf(dev, "Unable to allocate RX ring memory\n"); - error = ENOMEM; - goto rx_fail; - } - - /* For the ring itself */ - tsize = roundup2(adapter->num_tx_desc * - sizeof(union ixgbe_adv_tx_desc), DBA_ALIGN); - - /* - * 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 (int i = 0; i < adapter->num_queues; i++, txconf++) { - /* Set up some basics */ - txr = &adapter->tx_rings[i]; - txr->adapter = adapter; - txr->me = i; - - /* Initialize the TX side lock */ - IXGBE_TX_LOCK_INIT(txr); - - if (ixgbe_dma_malloc(adapter, tsize, - &txr->txdma, BUS_DMA_NOWAIT)) { - device_printf(dev, - "Unable to allocate TX Descriptor memory\n"); - error = ENOMEM; - goto err_tx_desc; - } - txr->tx_base = (union ixgbe_adv_tx_desc *)txr->txdma.dma_vaddr; - bzero((void *)txr->tx_base, tsize); - - /* Now allocate transmit buffers for the ring */ - if (ixgbe_allocate_transmit_buffers(txr)) { - device_printf(dev, - "Critical Failure setting up transmit buffers\n"); - error = ENOMEM; - goto err_tx_desc; - } -#if 0 /* __FreeBSD_version >= 800000 */ - /* Allocate a buf ring */ - txr->br = buf_ring_alloc(IXGBE_BR_SIZE, M_DEVBUF, - M_WAITOK, &txr->tx_mtx); - if (txr->br == NULL) { - device_printf(dev, - "Critical Failure setting up buf ring\n"); - error = ENOMEM; - goto err_tx_desc; - } -#endif - } - - /* - * Next the RX queues... - */ - rsize = roundup2(adapter->num_rx_desc * - sizeof(union ixgbe_adv_rx_desc), DBA_ALIGN); - for (int i = 0; i < adapter->num_queues; i++, rxconf++) { - rxr = &adapter->rx_rings[i]; - /* Set up some basics */ - rxr->adapter = adapter; - rxr->me = i; - - /* Initialize the RX side lock */ - ksnprintf(rxr->lock_name, sizeof(rxr->lock_name), "%s:rx(%d)", - device_get_nameunit(dev), rxr->me); - lockinit(&rxr->rx_lock, rxr->lock_name, 0, LK_CANRECURSE); - - if (ixgbe_dma_malloc(adapter, rsize, - &rxr->rxdma, BUS_DMA_NOWAIT)) { - device_printf(dev, - "Unable to allocate RxDescriptor memory\n"); - 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)) { - device_printf(dev, - "Critical Failure setting up receive buffers\n"); - error = ENOMEM; - goto err_rx_desc; - } - } - - /* - ** Finally set up the queue holding structs - */ - for (int i = 0; i < adapter->num_queues; i++) { - que = &adapter->queues[i]; - que->adapter = adapter; - que->txr = &adapter->tx_rings[i]; - que->rxr = &adapter->rx_rings[i]; - } - - return (0); - -err_rx_desc: - for (rxr = adapter->rx_rings; rxconf > 0; rxr++, rxconf--) - ixgbe_dma_free(adapter, &rxr->rxdma); -err_tx_desc: - for (txr = adapter->tx_rings; txconf > 0; txr++, txconf--) - ixgbe_dma_free(adapter, &txr->txdma); - kfree(adapter->rx_rings, M_DEVBUF); -rx_fail: - kfree(adapter->tx_rings, M_DEVBUF); -tx_fail: - kfree(adapter->queues, 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. - * - **********************************************************************/ -static int -ixgbe_allocate_transmit_buffers(struct tx_ring *txr) -{ - struct adapter *adapter = txr->adapter; - device_t dev = adapter->dev; - struct ixgbe_tx_buf *txbuf; - int error, i; - - /* - * Setup DMA descriptor areas. - */ - if ((error = bus_dma_tag_create( - NULL, /* parent */ - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - IXGBE_TSO_SIZE, /* maxsize */ - adapter->num_segs, /* nsegments */ - PAGE_SIZE, /* maxsegsize */ - 0, /* flags */ - &txr->txtag))) { - device_printf(dev,"Unable to allocate TX DMA tag\n"); - goto fail; - } - - if (!(txr->tx_buffers = - (struct ixgbe_tx_buf *) kmalloc(sizeof(struct ixgbe_tx_buf) * - adapter->num_tx_desc, M_DEVBUF, M_NOWAIT | M_ZERO))) { - device_printf(dev, "Unable to allocate tx_buffer memory\n"); - error = ENOMEM; - goto fail; - } - - /* Create the descriptor buffer dma maps */ - txbuf = txr->tx_buffers; - for (i = 0; i < adapter->num_tx_desc; i++, txbuf++) { - error = bus_dmamap_create(txr->txtag, 0, &txbuf->map); - if (error != 0) { - device_printf(dev, "Unable to create TX DMA map\n"); - goto fail; - } - } - - return 0; -fail: - /* We free all, it handles case where we are in the middle */ - ixgbe_free_transmit_structures(adapter); - return (error); -} - -/********************************************************************* - * - * Initialize a transmit ring. - * - **********************************************************************/ -static void -ixgbe_setup_transmit_ring(struct tx_ring *txr) -{ - struct adapter *adapter = txr->adapter; - struct ixgbe_tx_buf *txbuf; - int i; -#ifdef DEV_NETMAP - struct netmap_adapter *na = NA(adapter->ifp); - struct netmap_slot *slot; -#endif /* DEV_NETMAP */ - - /* Clear the old ring contents */ - IXGBE_TX_LOCK(txr); -#ifdef DEV_NETMAP - /* - * (under lock): if in netmap mode, do some consistency - * checks and set slot to entry 0 of the netmap ring. - */ - slot = netmap_reset(na, NR_TX, txr->me, 0); -#endif /* DEV_NETMAP */ - bzero((void *)txr->tx_base, - (sizeof(union ixgbe_adv_tx_desc)) * adapter->num_tx_desc); - /* Reset indices */ - txr->next_avail_desc = 0; - txr->next_to_clean = 0; - - /* Free any existing tx buffers. */ - txbuf = txr->tx_buffers; - for (i = 0; i < adapter->num_tx_desc; i++, txbuf++) { - if (txbuf->m_head != NULL) { - bus_dmamap_sync(txr->txtag, txbuf->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(txr->txtag, txbuf->map); - m_freem(txbuf->m_head); - txbuf->m_head = NULL; - } -#ifdef DEV_NETMAP - /* - * In netmap mode, set the map for the packet buffer. - * NOTE: Some drivers (not this one) also need to set - * the physical buffer address in the NIC ring. - * Slots in the netmap ring (indexed by "si") are - * kring->nkr_hwofs positions "ahead" wrt the - * corresponding slot in the NIC ring. In some drivers - * (not here) nkr_hwofs can be negative. Function - * netmap_idx_n2k() handles wraparounds properly. - */ - if (slot) { - int si = netmap_idx_n2k(&na->tx_rings[txr->me], i); - netmap_load_map(txr->txtag, txbuf->map, NMB(slot + si)); - } -#endif /* DEV_NETMAP */ - /* Clear the EOP index */ - txbuf->eop_index = -1; - } - -#ifdef IXGBE_FDIR - /* Set the rate at which we sample packets */ - if (adapter->hw.mac.type != ixgbe_mac_82598EB) - txr->atr_sample = atr_sample_rate; -#endif - - /* Set number of descriptors available */ - txr->tx_avail = adapter->num_tx_desc; - - bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - IXGBE_TX_UNLOCK(txr); -} - -/********************************************************************* - * - * Initialize all transmit rings. - * - **********************************************************************/ -static int -ixgbe_setup_transmit_structures(struct adapter *adapter) -{ - struct tx_ring *txr = adapter->tx_rings; - - for (int i = 0; i < adapter->num_queues; i++, txr++) - ixgbe_setup_transmit_ring(txr); - - return (0); -} - -/********************************************************************* - * - * Enable transmit unit. - * - **********************************************************************/ -static void -ixgbe_initialize_transmit_units(struct adapter *adapter) -{ - struct tx_ring *txr = adapter->tx_rings; - struct ixgbe_hw *hw = &adapter->hw; - - /* Setup the Base and Length of the Tx Descriptor Ring */ - - for (int i = 0; i < adapter->num_queues; i++, txr++) { - u64 tdba = txr->txdma.dma_paddr; - u32 txctrl; - - 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), - adapter->num_tx_desc * sizeof(struct ixgbe_legacy_tx_desc)); - - /* 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->queue_status = IXGBE_QUEUE_IDLE; - - /* Disable Head Writeback */ - switch (hw->mac.type) { - case ixgbe_mac_82598EB: - txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i)); - break; - case ixgbe_mac_82599EB: - case ixgbe_mac_X540: - default: - txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i)); - break; - } - txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; - switch (hw->mac.type) { - case ixgbe_mac_82598EB: - IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), txctrl); - break; - case ixgbe_mac_82599EB: - case ixgbe_mac_X540: - default: - IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), txctrl); - break; - } - - } - - if (hw->mac.type != ixgbe_mac_82598EB) { - u32 dmatxctl, rttdcs; - dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); - dmatxctl |= IXGBE_DMATXCTL_TE; - IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); - /* Disable arbiter to set MTQC */ - rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); - rttdcs |= IXGBE_RTTDCS_ARBDIS; - IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); - IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); - rttdcs &= ~IXGBE_RTTDCS_ARBDIS; - IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); - } - - return; -} - -/********************************************************************* - * - * Free all transmit rings. - * - **********************************************************************/ -static void -ixgbe_free_transmit_structures(struct adapter *adapter) -{ - struct tx_ring *txr = adapter->tx_rings; - - for (int i = 0; i < adapter->num_queues; i++, txr++) { - IXGBE_TX_LOCK(txr); - ixgbe_free_transmit_buffers(txr); - ixgbe_dma_free(adapter, &txr->txdma); - IXGBE_TX_UNLOCK(txr); - IXGBE_TX_LOCK_DESTROY(txr); - } - kfree(adapter->tx_rings, M_DEVBUF); -} - -/********************************************************************* - * - * Free transmit ring related data structures. - * - **********************************************************************/ -static void -ixgbe_free_transmit_buffers(struct tx_ring *txr) -{ - struct adapter *adapter = txr->adapter; - 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 < adapter->num_tx_desc; i++, tx_buffer++) { - if (tx_buffer->m_head != NULL) { - bus_dmamap_sync(txr->txtag, tx_buffer->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(txr->txtag, - tx_buffer->map); - m_freem(tx_buffer->m_head); - tx_buffer->m_head = NULL; - if (tx_buffer->map != NULL) { - bus_dmamap_destroy(txr->txtag, - tx_buffer->map); - tx_buffer->map = NULL; - } - } else if (tx_buffer->map != NULL) { - bus_dmamap_unload(txr->txtag, - tx_buffer->map); - bus_dmamap_destroy(txr->txtag, - tx_buffer->map); - tx_buffer->map = NULL; - } - } -#if 0 /* __FreeBSD_version >= 800000 */ - if (txr->br != NULL) - buf_ring_free(txr->br, M_DEVBUF); -#endif - if (txr->tx_buffers != NULL) { - kfree(txr->tx_buffers, M_DEVBUF); - txr->tx_buffers = NULL; - } - if (txr->txtag != NULL) { - bus_dma_tag_destroy(txr->txtag); - txr->txtag = NULL; - } - return; -} - -/********************************************************************* - * - * Advanced Context Descriptor setup for VLAN or CSUM - * - **********************************************************************/ - -static bool -ixgbe_tx_ctx_setup(struct tx_ring *txr, struct mbuf *mp) -{ - struct adapter *adapter = txr->adapter; - struct ixgbe_adv_tx_context_desc *TXD; - struct ixgbe_tx_buf *tx_buffer; - u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; - struct ether_vlan_header *eh; - 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_desc; - u16 vtag = 0; - - - if ((mp->m_pkthdr.csum_flags & CSUM_OFFLOAD) == 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 (mp->m_flags & M_VLANTAG) { - vtag = htole16(mp->m_pkthdr.ether_vlantag); - vlan_macip_lens |= (vtag << IXGBE_ADVTXD_VLAN_SHIFT); - } else if (offload == FALSE) - return FALSE; - - /* - * Determine where frame payload starts. - * Jump over vlan headers if already present, - * helpful for QinQ too. - */ - 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; - } - - /* 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; - ipproto = ip->ip_p; - 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); - /* XXX-BZ this will go badly in case of ext hdrs. */ - ipproto = ip6->ip6_nxt; - 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 & CSUM_TCP) - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; - break; - - case IPPROTO_UDP: - if (mp->m_pkthdr.csum_flags & CSUM_UDP) - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_UDP; - break; - -#if 0 - case IPPROTO_SCTP: - if (mp->m_pkthdr.csum_flags & CSUM_SCTP) - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_SCTP; - break; -#endif - 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); - - tx_buffer->m_head = NULL; - tx_buffer->eop_index = -1; - - /* We've consumed the first desc, adjust counters */ - if (++ctxd == adapter->num_tx_desc) - ctxd = 0; - txr->next_avail_desc = ctxd; - --txr->tx_avail; - - return (offload); -} - -/********************************************************************** - * - * Setup work for hardware segmentation offload (TSO) on - * adapters using advanced tx descriptors - * - **********************************************************************/ -static bool -ixgbe_tso_setup(struct tx_ring *txr, struct mbuf *mp, u32 *paylen, - u32 *olinfo_status) -{ - struct adapter *adapter = txr->adapter; - struct ixgbe_adv_tx_context_desc *TXD; - struct ixgbe_tx_buf *tx_buffer; - u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0; - u16 vtag = 0, eh_type; - u32 mss_l4len_idx = 0, len; - int ctxd, ehdrlen, ip_hlen, tcp_hlen; - struct ether_vlan_header *eh; -#if 0 /* IPv6 TSO */ -#ifdef INET6 - struct ip6_hdr *ip6; -#endif -#endif -#ifdef INET - struct ip *ip; -#endif - struct tcphdr *th; - - - /* - * Determine where frame payload starts. - * Jump over vlan headers if already present - */ - eh = mtod(mp, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - eh_type = eh->evl_proto; - } else { - ehdrlen = ETHER_HDR_LEN; - eh_type = eh->evl_encap_proto; - } - - /* Ensure we have at least the IP+TCP header in the first mbuf. */ - len = ehdrlen + sizeof(struct tcphdr); - switch (ntohs(eh_type)) { -#if 0 /* IPv6 TSO */ -#ifdef INET6 - case ETHERTYPE_IPV6: - if (mp->m_len < len + sizeof(struct ip6_hdr)) - return FALSE; - ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); - /* XXX-BZ For now we do not pretend to support ext. hdrs. */ - if (ip6->ip6_nxt != IPPROTO_TCP) - return FALSE; - ip_hlen = sizeof(struct ip6_hdr); - th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); - th->th_sum = in6_cksum_pseudo(ip6, 0, IPPROTO_TCP, 0); - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV6; - break; -#endif -#endif -#ifdef INET - case ETHERTYPE_IP: - if (mp->m_len < len + sizeof(struct ip)) - return FALSE; - ip = (struct ip *)(mp->m_data + ehdrlen); - if (ip->ip_p != IPPROTO_TCP) - return FALSE; - 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)); - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; - /* Tell transmit desc to also do IPv4 checksum. */ - *olinfo_status |= IXGBE_TXD_POPTS_IXSM << 8; - break; -#endif - default: - panic("%s: CSUM_TSO but no supported IP version (0x%04x)", - __func__, ntohs(eh_type)); - break; - } - - ctxd = txr->next_avail_desc; - tx_buffer = &txr->tx_buffers[ctxd]; - TXD = (struct ixgbe_adv_tx_context_desc *) &txr->tx_base[ctxd]; - - tcp_hlen = th->th_off << 2; - - /* This is used in the transmit desc in encap */ - *paylen = mp->m_pkthdr.len - ehdrlen - ip_hlen - tcp_hlen; - - /* VLAN MACLEN IPLEN */ - if (mp->m_flags & M_VLANTAG) { - vtag = htole16(mp->m_pkthdr.ether_vlantag); - vlan_macip_lens |= (vtag << IXGBE_ADVTXD_VLAN_SHIFT); - } - - 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; - 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; - tx_buffer->eop_index = -1; - - if (++ctxd == adapter->num_tx_desc) - ctxd = 0; - - txr->tx_avail--; - txr->next_avail_desc = ctxd; - return TRUE; -} - -#ifdef IXGBE_FDIR -/* -** This routine parses packet headers so that Flow -** Director can make a hashed filter table entry -** allowing traffic flows to be identified and kept -** on the same cpu. This would be a performance -** hit, but we only do it at IXGBE_FDIR_RATE of -** packets. -*/ -static void -ixgbe_atr(struct tx_ring *txr, struct mbuf *mp) -{ - struct adapter *adapter = txr->adapter; - struct ix_queue *que; - struct ip *ip; - struct tcphdr *th; - struct udphdr *uh; - struct ether_vlan_header *eh; - union ixgbe_atr_hash_dword input = {.dword = 0}; - union ixgbe_atr_hash_dword common = {.dword = 0}; - int ehdrlen, ip_hlen; - u16 etype; - - eh = mtod(mp, struct ether_vlan_header *); - if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { - ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; - etype = eh->evl_proto; - } else { - ehdrlen = ETHER_HDR_LEN; - etype = eh->evl_encap_proto; - } - - /* Only handling IPv4 */ - if (etype != htons(ETHERTYPE_IP)) - return; - - ip = (struct ip *)(mp->m_data + ehdrlen); - ip_hlen = ip->ip_hl << 2; - - /* check if we're UDP or TCP */ - switch (ip->ip_p) { - case IPPROTO_TCP: - th = (struct tcphdr *)((caddr_t)ip + ip_hlen); - /* src and dst are inverted */ - common.port.dst ^= th->th_sport; - common.port.src ^= th->th_dport; - input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_TCPV4; - break; - case IPPROTO_UDP: - uh = (struct udphdr *)((caddr_t)ip + ip_hlen); - /* src and dst are inverted */ - common.port.dst ^= uh->uh_sport; - common.port.src ^= uh->uh_dport; - input.formatted.flow_type ^= IXGBE_ATR_FLOW_TYPE_UDPV4; - break; - default: - return; - } - - input.formatted.vlan_id = htobe16(mp->m_pkthdr.ether_vtag); - if (mp->m_pkthdr.ether_vtag) - common.flex_bytes ^= htons(ETHERTYPE_VLAN); - else - common.flex_bytes ^= etype; - common.ip ^= ip->ip_src.s_addr ^ ip->ip_dst.s_addr; - - que = &adapter->queues[txr->me]; - /* - ** This assumes the Rx queue and Tx - ** queue are bound to the same CPU - */ - ixgbe_fdir_add_signature_filter_82599(&adapter->hw, - input, common, que->msix); -} -#endif /* IXGBE_FDIR */ - -/********************************************************************** - * - * 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. - * - **********************************************************************/ -static void -ixgbe_txeof(struct tx_ring *txr) -{ - struct adapter *adapter = txr->adapter; - struct ifnet *ifp = adapter->ifp; - u32 first, last, done, processed; - struct ixgbe_tx_buf *tx_buffer; - struct ixgbe_legacy_tx_desc *tx_desc, *eop_desc; - - IXGBE_TX_LOCK_ASSERT(txr); - -#ifdef DEV_NETMAP - if (ifp->if_capenable & IFCAP_NETMAP) { - struct netmap_adapter *na = NA(ifp); - struct netmap_kring *kring = &na->tx_rings[txr->me]; - - tx_desc = (struct ixgbe_legacy_tx_desc *)txr->tx_base; - - bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, - BUS_DMASYNC_POSTREAD); - /* - * In netmap mode, all the work is done in the context - * of the client thread. Interrupt handlers only wake up - * clients, which may be sleeping on individual rings - * or on a global resource for all rings. - * To implement tx interrupt mitigation, we wake up the client - * thread roughly every half ring, even if the NIC interrupts - * more frequently. This is implemented as follows: - * - ixgbe_txsync() sets kring->nr_kflags with the index of - * the slot that should wake up the thread (nkr_num_slots - * means the user thread should not be woken up); - * - the driver ignores tx interrupts unless netmap_mitigate=0 - * or the slot has the DD bit set. - * - * When the driver has separate locks, we need to - * release and re-acquire txlock to avoid deadlocks. - * XXX see if we can find a better way. - */ - if (!netmap_mitigate || - (kring->nr_kflags < kring->nkr_num_slots && - tx_desc[kring->nr_kflags].upper.fields.status & IXGBE_TXD_STAT_DD)) { - kring->nr_kflags = kring->nkr_num_slots; - selwakeuppri(&na->tx_rings[txr->me].si, PI_NET); - IXGBE_TX_UNLOCK(txr); - IXGBE_CORE_LOCK(adapter); - selwakeuppri(&na->tx_si, PI_NET); - IXGBE_CORE_UNLOCK(adapter); - IXGBE_TX_LOCK(txr); - } - return FALSE; - } -#endif /* DEV_NETMAP */ - - if (txr->tx_avail == adapter->num_tx_desc) { - txr->queue_status = IXGBE_QUEUE_IDLE; - return; - } - - processed = 0; - first = txr->next_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]; - last = tx_buffer->eop_index; - if (last == -1) - return; - eop_desc = (struct ixgbe_legacy_tx_desc *)&txr->tx_base[last]; - - /* - ** Get the index of the first descriptor - ** BEYOND the EOP and call that 'done'. - ** I do this so the comparison in the - ** inner while loop below can be simple - */ - if (++last == adapter->num_tx_desc) last = 0; - done = last; - - bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, - BUS_DMASYNC_POSTREAD); - /* - ** Only the EOP descriptor of a packet now has the DD - ** bit set, this is what we look for... - */ - while (eop_desc->upper.fields.status & IXGBE_TXD_STAT_DD) { - /* We clean the range of the packet */ - while (first != done) { - tx_desc->upper.data = 0; - tx_desc->lower.data = 0; - tx_desc->buffer_addr = 0; - ++txr->tx_avail; - ++processed; - - if (tx_buffer->m_head) { - txr->bytes += - tx_buffer->m_head->m_pkthdr.len; - bus_dmamap_sync(txr->txtag, - tx_buffer->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(txr->txtag, - tx_buffer->map); - m_freem(tx_buffer->m_head); - tx_buffer->m_head = NULL; - tx_buffer->map = NULL; - } - tx_buffer->eop_index = -1; - txr->watchdog_time = ticks; - - if (++first == adapter->num_tx_desc) - first = 0; - - tx_buffer = &txr->tx_buffers[first]; - tx_desc = - (struct ixgbe_legacy_tx_desc *)&txr->tx_base[first]; - } - ++txr->packets; - IFNET_STAT_INC(ifp, opackets, 1); - /* See if there is more work now */ - last = tx_buffer->eop_index; - if (last != -1) { - eop_desc = - (struct ixgbe_legacy_tx_desc *)&txr->tx_base[last]; - /* Get next done point */ - if (++last == adapter->num_tx_desc) last = 0; - done = last; - } else - break; - } - bus_dmamap_sync(txr->txdma.dma_tag, txr->txdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - - txr->next_to_clean = first; - - /* - ** Watchdog calculation, we know there's - ** work outstanding or the first return - ** would have been taken, so none processed - ** for too long indicates a hang. - */ - if ((!processed) && ((ticks - txr->watchdog_time) > IXGBE_WATCHDOG)) - txr->queue_status = IXGBE_QUEUE_HUNG; - - /* With a minimum free clear the depleted state bit. */ - if (txr->tx_avail > IXGBE_TX_CLEANUP_THRESHOLD) - txr->queue_status &= ~IXGBE_QUEUE_DEPLETED; - - if (txr->tx_avail == adapter->num_tx_desc) { - txr->queue_status = IXGBE_QUEUE_IDLE; - } -} - -/********************************************************************* - * - * Refresh mbuf buffers for RX descriptor rings - * - now keeps its own state so discards due to resource - * exhaustion are unnecessary, if an mbuf cannot be obtained - * it just returns, keeping its placeholder, thus it can simply - * be recalled to try again. - * - **********************************************************************/ -static void -ixgbe_refresh_mbufs(struct rx_ring *rxr, int limit) -{ - struct adapter *adapter = rxr->adapter; - bus_dma_segment_t hseg[1]; - bus_dma_segment_t pseg[1]; - struct ixgbe_rx_buf *rxbuf; - struct mbuf *mh, *mp; - int i, j, nsegs, error; - bool refreshed = FALSE; - - i = j = rxr->next_to_refresh; - /* Control the loop with one beyond */ - if (++j == adapter->num_rx_desc) - j = 0; - - while (j != limit) { - rxbuf = &rxr->rx_buffers[i]; - if (rxr->hdr_split == FALSE) - goto no_split; - - if (rxbuf->m_head == NULL) { - mh = m_gethdr(MB_DONTWAIT, MT_DATA); - if (mh == NULL) - goto update; - } else - mh = rxbuf->m_head; - - mh->m_pkthdr.len = mh->m_len = MHLEN; - mh->m_len = MHLEN; - mh->m_flags |= M_PKTHDR; - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_segment(rxr->htag, - rxbuf->hmap, mh, hseg, 1, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - kprintf("Refresh mbufs: hdr dmamap load" - " failure - %d\n", error); - m_free(mh); - rxbuf->m_head = NULL; - goto update; - } - rxbuf->m_head = mh; - bus_dmamap_sync(rxr->htag, rxbuf->hmap, - BUS_DMASYNC_PREREAD); - rxr->rx_base[i].read.hdr_addr = - htole64(hseg[0].ds_addr); - -no_split: - if (rxbuf->m_pack == NULL) { - mp = m_getjcl(MB_DONTWAIT, MT_DATA, - M_PKTHDR, adapter->rx_mbuf_sz); - if (mp == NULL) - goto update; - } else - mp = rxbuf->m_pack; - - mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz; - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_segment(rxr->ptag, - rxbuf->pmap, mp, pseg, 1, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) { - kprintf("Refresh mbufs: payload dmamap load" - " failure - %d\n", error); - m_free(mp); - rxbuf->m_pack = NULL; - goto update; - } - rxbuf->m_pack = mp; - bus_dmamap_sync(rxr->ptag, rxbuf->pmap, - BUS_DMASYNC_PREREAD); - rxr->rx_base[i].read.pkt_addr = - htole64(pseg[0].ds_addr); - - refreshed = TRUE; - /* Next is precalculated */ - i = j; - rxr->next_to_refresh = i; - if (++j == adapter->num_rx_desc) - j = 0; - } -update: - if (refreshed) /* Update hardware tail index */ - IXGBE_WRITE_REG(&adapter->hw, - IXGBE_RDT(rxr->me), rxr->next_to_refresh); - return; -} - -/********************************************************************* - * - * 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. - * - **********************************************************************/ -static int -ixgbe_allocate_receive_buffers(struct rx_ring *rxr) -{ - struct adapter *adapter = rxr->adapter; - device_t dev = adapter->dev; - struct ixgbe_rx_buf *rxbuf; - int i, bsize, error; - - bsize = sizeof(struct ixgbe_rx_buf) * adapter->num_rx_desc; - if (!(rxr->rx_buffers = - (struct ixgbe_rx_buf *) kmalloc(bsize, - M_DEVBUF, M_NOWAIT | M_ZERO))) { - device_printf(dev, "Unable to allocate rx_buffer memory\n"); - error = ENOMEM; - goto fail; - } - - if ((error = bus_dma_tag_create(NULL, /* parent */ - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MSIZE, /* maxsize */ - 1, /* nsegments */ - MSIZE, /* maxsegsize */ - 0, /* flags */ - &rxr->htag))) { - device_printf(dev, "Unable to create RX DMA tag\n"); - goto fail; - } - - if ((error = bus_dma_tag_create(NULL, /* parent */ - 1, 0, /* alignment, bounds */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MJUM16BYTES, /* maxsize */ - 1, /* nsegments */ - MJUM16BYTES, /* maxsegsize */ - 0, /* flags */ - &rxr->ptag))) { - device_printf(dev, "Unable to create RX DMA tag\n"); - goto fail; - } - - for (i = 0; i < adapter->num_rx_desc; i++, rxbuf++) { - rxbuf = &rxr->rx_buffers[i]; - error = bus_dmamap_create(rxr->htag, - BUS_DMA_NOWAIT, &rxbuf->hmap); - if (error) { - device_printf(dev, "Unable to create RX head map\n"); - goto fail; - } - error = bus_dmamap_create(rxr->ptag, - BUS_DMA_NOWAIT, &rxbuf->pmap); - if (error) { - device_printf(dev, "Unable to create RX pkt map\n"); - goto fail; - } - } - - return (0); - -fail: - /* Frees all, but can handle partial completion */ - ixgbe_free_receive_structures(adapter); - return (error); -} - -/* -** Used to detect a descriptor that has -** been merged by Hardware RSC. -*/ -static inline u32 -ixgbe_rsc_count(union ixgbe_adv_rx_desc *rx) -{ - return (le32toh(rx->wb.lower.lo_dword.data) & - IXGBE_RXDADV_RSCCNT_MASK) >> IXGBE_RXDADV_RSCCNT_SHIFT; -} - -/********************************************************************* - * - * Initialize Hardware RSC (LRO) feature on 82599 - * for an RX ring, this is toggled by the LRO capability - * even though it is transparent to the stack. - * - **********************************************************************/ -#if 0 /* NET_LRO */ -static void -ixgbe_setup_hw_rsc(struct rx_ring *rxr) -{ - struct adapter *adapter = rxr->adapter; - struct ixgbe_hw *hw = &adapter->hw; - u32 rscctrl, rdrxctl; - - rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); - rdrxctl &= ~IXGBE_RDRXCTL_RSCFRSTSIZE; -#ifdef DEV_NETMAP /* crcstrip is optional in netmap */ - if (adapter->ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) -#endif /* DEV_NETMAP */ - rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP; - rdrxctl |= IXGBE_RDRXCTL_RSCACKC; - IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); - - rscctrl = IXGBE_READ_REG(hw, IXGBE_RSCCTL(rxr->me)); - rscctrl |= IXGBE_RSCCTL_RSCEN; - /* - ** Limit the total number of descriptors that - ** can be combined, so it does not exceed 64K - */ - if (adapter->rx_mbuf_sz == MCLBYTES) - rscctrl |= IXGBE_RSCCTL_MAXDESC_16; - else if (adapter->rx_mbuf_sz == MJUMPAGESIZE) - rscctrl |= IXGBE_RSCCTL_MAXDESC_8; - else if (adapter->rx_mbuf_sz == MJUM9BYTES) - rscctrl |= IXGBE_RSCCTL_MAXDESC_4; - else /* Using 16K cluster */ - rscctrl |= IXGBE_RSCCTL_MAXDESC_1; - - IXGBE_WRITE_REG(hw, IXGBE_RSCCTL(rxr->me), rscctrl); - - /* Enable TCP header recognition */ - IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), - (IXGBE_READ_REG(hw, IXGBE_PSRTYPE(0)) | - IXGBE_PSRTYPE_TCPHDR)); - - /* Disable RSC for ACK packets */ - IXGBE_WRITE_REG(hw, IXGBE_RSCDBU, - (IXGBE_RSCDBU_RSCACKDIS | IXGBE_READ_REG(hw, IXGBE_RSCDBU))); - - rxr->hw_rsc = TRUE; -} -#endif - -static void -ixgbe_free_receive_ring(struct rx_ring *rxr) -{ - struct adapter *adapter; - struct ixgbe_rx_buf *rxbuf; - int i; - - adapter = rxr->adapter; - for (i = 0; i < adapter->num_rx_desc; i++) { - rxbuf = &rxr->rx_buffers[i]; - if (rxbuf->m_head != NULL) { - bus_dmamap_sync(rxr->htag, rxbuf->hmap, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->htag, rxbuf->hmap); - rxbuf->m_head->m_flags |= M_PKTHDR; - m_freem(rxbuf->m_head); - } - if (rxbuf->m_pack != NULL) { - bus_dmamap_sync(rxr->ptag, rxbuf->pmap, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->ptag, rxbuf->pmap); - rxbuf->m_pack->m_flags |= M_PKTHDR; - m_freem(rxbuf->m_pack); - } - rxbuf->m_head = NULL; - rxbuf->m_pack = NULL; - } -} - - -/********************************************************************* - * - * Initialize a receive ring and its buffers. - * - **********************************************************************/ -static int -ixgbe_setup_receive_ring(struct rx_ring *rxr) -{ - struct adapter *adapter; -#if 0 /* NET_LRO */ - struct ifnet *ifp; - device_t dev; -#endif - struct ixgbe_rx_buf *rxbuf; - bus_dma_segment_t pseg[1], hseg[1]; -#if 0 /* NET_LRO */ - struct lro_ctrl *lro = &rxr->lro; -#endif - int rsize, nsegs, error = 0; -#ifdef DEV_NETMAP - struct netmap_adapter *na = NA(rxr->adapter->ifp); - struct netmap_slot *slot; -#endif /* DEV_NETMAP */ - - adapter = rxr->adapter; -#if 0 /* NET_LRO */ - ifp = adapter->ifp; - dev = adapter->dev; -#endif - - /* Clear the ring contents */ - IXGBE_RX_LOCK(rxr); -#ifdef DEV_NETMAP - /* same as in ixgbe_setup_transmit_ring() */ - slot = netmap_reset(na, NR_RX, rxr->me, 0); -#endif /* DEV_NETMAP */ - rsize = roundup2(adapter->num_rx_desc * - sizeof(union ixgbe_adv_rx_desc), DBA_ALIGN); - bzero((void *)rxr->rx_base, rsize); - - /* Free current RX buffer structs and their mbufs */ - ixgbe_free_receive_ring(rxr); - - /* Configure header split? */ - if (ixgbe_header_split) - rxr->hdr_split = TRUE; - - /* Now replenish the mbufs */ - for (int j = 0; j != adapter->num_rx_desc; ++j) { - struct mbuf *mh, *mp; - - rxbuf = &rxr->rx_buffers[j]; -#ifdef DEV_NETMAP - /* - * In netmap mode, fill the map and set the buffer - * address in the NIC ring, considering the offset - * between the netmap and NIC rings (see comment in - * ixgbe_setup_transmit_ring() ). No need to allocate - * an mbuf, so end the block with a continue; - */ - if (slot) { - int sj = netmap_idx_n2k(&na->rx_rings[rxr->me], j); - uint64_t paddr; - void *addr; - - addr = PNMB(slot + sj, &paddr); - netmap_load_map(rxr->ptag, rxbuf->pmap, addr); - /* Update descriptor */ - rxr->rx_base[j].read.pkt_addr = htole64(paddr); - continue; - } -#endif /* DEV_NETMAP */ - /* - ** Don't allocate mbufs if not - ** doing header split, its wasteful - */ - if (rxr->hdr_split == FALSE) - goto skip_head; - - /* First the header */ - rxbuf->m_head = m_gethdr(MB_DONTWAIT, MT_DATA); - if (rxbuf->m_head == NULL) { - error = ENOBUFS; - goto fail; - } - m_adj(rxbuf->m_head, ETHER_ALIGN); - mh = rxbuf->m_head; - mh->m_len = mh->m_pkthdr.len = MHLEN; - mh->m_flags |= M_PKTHDR; - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_segment(rxr->htag, - rxbuf->hmap, rxbuf->m_head, hseg, 1, - &nsegs, BUS_DMA_NOWAIT); - - if (error != 0) /* Nothing elegant to do here */ - goto fail; - bus_dmamap_sync(rxr->htag, - rxbuf->hmap, BUS_DMASYNC_PREREAD); - /* Update descriptor */ - rxr->rx_base[j].read.hdr_addr = htole64(hseg[0].ds_addr); - -skip_head: - /* Now the payload cluster */ - rxbuf->m_pack = m_getjcl(MB_DONTWAIT, MT_DATA, - M_PKTHDR, adapter->rx_mbuf_sz); - if (rxbuf->m_pack == NULL) { - error = ENOBUFS; - goto fail; - } - mp = rxbuf->m_pack; - mp->m_pkthdr.len = mp->m_len = adapter->rx_mbuf_sz; - /* Get the memory mapping */ - error = bus_dmamap_load_mbuf_segment(rxr->ptag, - rxbuf->pmap, mp, hseg, 1, - &nsegs, BUS_DMA_NOWAIT); - if (error != 0) - goto fail; - bus_dmamap_sync(rxr->ptag, - rxbuf->pmap, BUS_DMASYNC_PREREAD); - /* Update descriptor */ - rxr->rx_base[j].read.pkt_addr = htole64(pseg[0].ds_addr); - } - - - /* Setup our descriptor indices */ - rxr->next_to_check = 0; - rxr->next_to_refresh = 0; - rxr->lro_enabled = FALSE; - rxr->rx_split_packets = 0; - rxr->rx_bytes = 0; - rxr->discard = FALSE; - rxr->vtag_strip = FALSE; - - bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - - /* - ** Now set up the LRO interface: - ** 82598 uses software LRO, the - ** 82599 and X540 use a hardware assist. - */ -#if 0 /* NET_LRO */ - if ((adapter->hw.mac.type != ixgbe_mac_82598EB) && - (ifp->if_capenable & IFCAP_RXCSUM) && - (ifp->if_capenable & IFCAP_LRO)) - ixgbe_setup_hw_rsc(rxr); - else if (ifp->if_capenable & IFCAP_LRO) { - int err = tcp_lro_init(lro); - if (err) { - device_printf(dev, "LRO Initialization failed!\n"); - goto fail; - } - INIT_DEBUGOUT("RX Soft LRO Initialized\n"); - rxr->lro_enabled = TRUE; - lro->ifp = adapter->ifp; - } -#endif - - IXGBE_RX_UNLOCK(rxr); - return (0); - -fail: - ixgbe_free_receive_ring(rxr); - IXGBE_RX_UNLOCK(rxr); - return (error); -} - -/********************************************************************* - * - * Initialize all receive rings. - * - **********************************************************************/ -static int -ixgbe_setup_receive_structures(struct adapter *adapter) -{ - struct rx_ring *rxr = adapter->rx_rings; - int j; - - for (j = 0; j < adapter->num_queues; j++, 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. 'j' failed, so its the terminus. - */ - for (int i = 0; i < j; ++i) { - rxr = &adapter->rx_rings[i]; - ixgbe_free_receive_ring(rxr); - } - - return (ENOBUFS); -} - -/********************************************************************* - * - * Setup receive registers and features. - * - **********************************************************************/ -#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 - -#define BSIZEPKT_ROUNDUP ((1<rx_rings; - struct ixgbe_hw *hw = &adapter->hw; - struct ifnet *ifp = adapter->ifp; - u32 bufsz, rxctrl, fctrl, srrctl, rxcsum; - u32 reta, mrqc = 0, hlreg, random[10]; - - - /* - * Make sure receives are disabled while - * setting up the descriptor ring - */ - rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); - IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, - rxctrl & ~IXGBE_RXCTRL_RXEN); - - /* Enable broadcasts */ - fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); - fctrl |= IXGBE_FCTRL_BAM; - fctrl |= IXGBE_FCTRL_DPF; - fctrl |= IXGBE_FCTRL_PMCF; - IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); - - /* Set for Jumbo Frames? */ - hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); - if (ifp->if_mtu > ETHERMTU) - hlreg |= IXGBE_HLREG0_JUMBOEN; - else - hlreg &= ~IXGBE_HLREG0_JUMBOEN; -#ifdef DEV_NETMAP - /* crcstrip is conditional in netmap (in RDRXCTL too ?) */ - if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) - hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; - else - hlreg |= IXGBE_HLREG0_RXCRCSTRP; -#endif /* DEV_NETMAP */ - IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); - - bufsz = (adapter->rx_mbuf_sz + - BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; - - for (int i = 0; i < adapter->num_queues; i++, rxr++) { - u64 rdba = rxr->rxdma.dma_paddr; - - /* Setup the Base and Length of the Rx Descriptor Ring */ - IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), - (rdba & 0x00000000ffffffffULL)); - IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32)); - IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), - adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); - - /* Set up the SRRCTL register */ - srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i)); - srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; - srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; - srrctl |= bufsz; - if (rxr->hdr_split) { - /* Use a standard mbuf for the header */ - srrctl |= ((IXGBE_RX_HDR << - IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) - & IXGBE_SRRCTL_BSIZEHDR_MASK); - srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; - } else - srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; - IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(i), srrctl); - - /* Setup the HW Rx Head and Tail Descriptor Pointers */ - IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0); - IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0); - } - - if (adapter->hw.mac.type != ixgbe_mac_82598EB) { - u32 psrtype = IXGBE_PSRTYPE_TCPHDR | - IXGBE_PSRTYPE_UDPHDR | - IXGBE_PSRTYPE_IPV4HDR | - IXGBE_PSRTYPE_IPV6HDR; - IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); - } - - rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); - - /* Setup RSS */ - if (adapter->num_queues > 1) { - int i, j; - reta = 0; - - /* set up random bits */ - karc4rand(&random, sizeof(random)); - - /* Set up the redirection table */ - for (i = 0, j = 0; i < 128; i++, j++) { - if (j == adapter->num_queues) j = 0; - reta = (reta << 8) | (j * 0x11); - if ((i & 3) == 3) - IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); - } - - /* Now fill our hash function seeds */ - for (int i = 0; i < 10; i++) - IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), random[i]); - - /* Perform hash on these packet types */ - mrqc = IXGBE_MRQC_RSSEN - | 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(hw, IXGBE_MRQC, mrqc); - - /* RSS and RX IPP Checksum are mutually exclusive */ - rxcsum |= IXGBE_RXCSUM_PCSD; - } - - if (ifp->if_capenable & IFCAP_RXCSUM) - rxcsum |= IXGBE_RXCSUM_PCSD; - - if (!(rxcsum & IXGBE_RXCSUM_PCSD)) - rxcsum |= IXGBE_RXCSUM_IPPCSE; - - IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); - - return; -} - -/********************************************************************* - * - * Free all receive rings. - * - **********************************************************************/ -static void -ixgbe_free_receive_structures(struct adapter *adapter) -{ - struct rx_ring *rxr = adapter->rx_rings; - - for (int i = 0; i < adapter->num_queues; i++, rxr++) { -#if 0 /* NET_LRO */ - struct lro_ctrl *lro = &rxr->lro; -#endif - ixgbe_free_receive_buffers(rxr); - /* Free LRO memory */ -#if 0 /* NET_LRO */ - tcp_lro_free(lro); -#endif - /* Free the ring memory as well */ - ixgbe_dma_free(adapter, &rxr->rxdma); - } - - kfree(adapter->rx_rings, M_DEVBUF); -} - - -/********************************************************************* - * - * Free receive ring data structures - * - **********************************************************************/ -static void -ixgbe_free_receive_buffers(struct rx_ring *rxr) -{ - struct adapter *adapter = rxr->adapter; - struct ixgbe_rx_buf *rxbuf; - - INIT_DEBUGOUT("free_receive_structures: begin"); - - /* Cleanup any existing buffers */ - if (rxr->rx_buffers != NULL) { - for (int i = 0; i < adapter->num_rx_desc; i++) { - rxbuf = &rxr->rx_buffers[i]; - if (rxbuf->m_head != NULL) { - bus_dmamap_sync(rxr->htag, rxbuf->hmap, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->htag, rxbuf->hmap); - rxbuf->m_head->m_flags |= M_PKTHDR; - m_freem(rxbuf->m_head); - } - if (rxbuf->m_pack != NULL) { - bus_dmamap_sync(rxr->ptag, rxbuf->pmap, - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rxr->ptag, rxbuf->pmap); - rxbuf->m_pack->m_flags |= M_PKTHDR; - m_freem(rxbuf->m_pack); - } - rxbuf->m_head = NULL; - rxbuf->m_pack = NULL; - if (rxbuf->hmap != NULL) { - bus_dmamap_destroy(rxr->htag, rxbuf->hmap); - rxbuf->hmap = NULL; - } - if (rxbuf->pmap != NULL) { - bus_dmamap_destroy(rxr->ptag, rxbuf->pmap); - rxbuf->pmap = NULL; - } - } - if (rxr->rx_buffers != NULL) { - kfree(rxr->rx_buffers, M_DEVBUF); - rxr->rx_buffers = NULL; - } - } - - if (rxr->htag != NULL) { - bus_dma_tag_destroy(rxr->htag); - rxr->htag = NULL; - } - if (rxr->ptag != NULL) { - bus_dma_tag_destroy(rxr->ptag); - rxr->ptag = NULL; - } - - return; -} - -static __inline void -ixgbe_rx_input(struct rx_ring *rxr, struct ifnet *ifp, struct mbuf *m, u32 ptype) -{ - - /* - * ATM LRO is only for IP/TCP packets and TCP checksum of the packet - * should be computed by hardware. Also it should not have VLAN tag in - * ethernet header. In case of IPv6 we do not yet support ext. hdrs. - */ -#if 0 /* NET_LRO */ - if (rxr->lro_enabled && - (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 && - (ptype & IXGBE_RXDADV_PKTTYPE_ETQF) == 0 && - ((ptype & (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP)) == - (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP) || - (ptype & (IXGBE_RXDADV_PKTTYPE_IPV6 | IXGBE_RXDADV_PKTTYPE_TCP)) == - (IXGBE_RXDADV_PKTTYPE_IPV6 | IXGBE_RXDADV_PKTTYPE_TCP)) && - (m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) == - (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) { - /* - * Send to the stack if: - ** - LRO not enabled, or - ** - no LRO resources, or - ** - lro enqueue fails - */ - if (rxr->lro.lro_cnt != 0) - if (tcp_lro_rx(&rxr->lro, m, 0) == 0) - return; - } -#endif - IXGBE_RX_UNLOCK(rxr); - (*ifp->if_input)(ifp, m); - IXGBE_RX_LOCK(rxr); -} - -static __inline void -ixgbe_rx_discard(struct rx_ring *rxr, int i) -{ - struct ixgbe_rx_buf *rbuf; - - rbuf = &rxr->rx_buffers[i]; - - if (rbuf->fmp != NULL) {/* Partial chain ? */ - rbuf->fmp->m_flags |= M_PKTHDR; - m_freem(rbuf->fmp); - rbuf->fmp = NULL; - } - - /* - ** With advanced descriptors the writeback - ** clobbers the buffer addrs, so its easier - ** to just free the existing mbufs and take - ** the normal refresh path to get new buffers - ** and mapping. - */ - if (rbuf->m_head) { - m_free(rbuf->m_head); - rbuf->m_head = NULL; - } - - if (rbuf->m_pack) { - m_free(rbuf->m_pack); - rbuf->m_pack = NULL; - } - - return; -} - -static void -ixgbe_add_sysctl(struct adapter *adapter) -{ - sysctl_ctx_init(&adapter->sysctl_ctx); - adapter->sysctl_tree = SYSCTL_ADD_NODE(&adapter->sysctl_ctx, - SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, - device_get_nameunit(adapter->dev), CTLFLAG_RD, 0, ""); - if (adapter->sysctl_tree == NULL) { - device_printf(adapter->dev, "can't add sysctl node\n"); - return; - } - SYSCTL_ADD_PROC(&adapter->sysctl_ctx, - SYSCTL_CHILDREN(adapter->sysctl_tree), - OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, - adapter, 0, ixgbe_set_flowcntl, "I", "Flow Control"); - - SYSCTL_ADD_PROC(&adapter->sysctl_ctx, - SYSCTL_CHILDREN(adapter->sysctl_tree), - OID_AUTO, "intr_rate", CTLTYPE_INT | CTLFLAG_RW, - adapter, 0, ixgbe_sysctl_intr_rate, "I", "interrupt rate"); - - /* - ** Allow a kind of speed control by forcing the autoneg - ** advertised speed list to only a certain value, this - ** supports 1G on 82599 devices, and 100Mb on x540. - */ - SYSCTL_ADD_PROC(&adapter->sysctl_ctx, - SYSCTL_CHILDREN(adapter->sysctl_tree), - OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, - adapter, 0, ixgbe_set_advertise, "I", "Link Speed"); - - SYSCTL_ADD_PROC(&adapter->sysctl_ctx, - SYSCTL_CHILDREN(adapter->sysctl_tree), - OID_AUTO, "ts", CTLTYPE_INT | CTLFLAG_RW, adapter, - 0, ixgbe_set_thermal_test, "I", "Thermal Test"); - - /* Sysctl for limiting the amount of work done in the taskqueue */ - ixgbe_add_rx_process_limit(adapter, "rx_processing_limit", - "max number of rx packets to process", &adapter->rx_process_limit, - ixgbe_rx_process_limit); -} - -/********************************************************************* - * - * 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. - * - * Return TRUE for more work, FALSE for all clean. - *********************************************************************/ -static void -ixgbe_rxeof(struct ix_queue *que, int count) -{ - struct adapter *adapter = que->adapter; - struct rx_ring *rxr = que->rxr; - struct ifnet *ifp = adapter->ifp; -#if 0 /* NET_LRO */ - struct lro_ctrl *lro = &rxr->lro; - struct lro_entry *queued; -#endif - int i, nextp, processed = 0; - u32 staterr = 0; - union ixgbe_adv_rx_desc *cur; - struct ixgbe_rx_buf *rbuf, *nbuf; - - IXGBE_RX_LOCK(rxr); - -#ifdef DEV_NETMAP - if (ifp->if_capenable & IFCAP_NETMAP) { - /* - * Same as the txeof routine: only wakeup clients on intr. - * NKR_PENDINTR in nr_kflags is used to implement interrupt - * mitigation (ixgbe_rxsync() will not look for new packets - * unless NKR_PENDINTR is set). - */ - struct netmap_adapter *na = NA(ifp); - - na->rx_rings[rxr->me].nr_kflags |= NKR_PENDINTR; - selwakeuppri(&na->rx_rings[rxr->me].si, PI_NET); - IXGBE_RX_UNLOCK(rxr); - IXGBE_CORE_LOCK(adapter); - selwakeuppri(&na->rx_si, PI_NET); - IXGBE_CORE_UNLOCK(adapter); - return (FALSE); - } -#endif /* DEV_NETMAP */ - for (i = rxr->next_to_check; count != 0;) { - struct mbuf *sendmp, *mh, *mp; - u32 rsc, ptype; - u16 hlen, plen, hdr; - u16 vtag = 0; - bool eop; - - /* Sync the ring. */ - bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - - cur = &rxr->rx_base[i]; - staterr = le32toh(cur->wb.upper.status_error); - - if ((staterr & IXGBE_RXD_STAT_DD) == 0) - break; - if ((ifp->if_flags & IFF_RUNNING) == 0) - break; - - count--; - sendmp = NULL; - nbuf = NULL; - rsc = 0; - cur->wb.upper.status_error = 0; - rbuf = &rxr->rx_buffers[i]; - mh = rbuf->m_head; - mp = rbuf->m_pack; - - plen = le16toh(cur->wb.upper.length); - ptype = le32toh(cur->wb.lower.lo_dword.data) & - IXGBE_RXDADV_PKTTYPE_MASK; - hdr = le16toh(cur->wb.lower.lo_dword.hs_rss.hdr_info); - eop = ((staterr & IXGBE_RXD_STAT_EOP) != 0); - - /* Process vlan info */ - if ((rxr->vtag_strip) && (staterr & IXGBE_RXD_STAT_VP)) - vtag = le16toh(cur->wb.upper.vlan); - - /* Make sure bad packets are discarded */ - if (((staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) != 0) || - (rxr->discard)) { - IFNET_STAT_INC(ifp, ierrors, 1); - rxr->rx_discarded++; - if (eop) - rxr->discard = FALSE; - else - rxr->discard = TRUE; - ixgbe_rx_discard(rxr, i); - goto next_desc; - } - - /* - ** On 82599 which supports a hardware - ** LRO (called HW RSC), packets need - ** not be fragmented across sequential - ** descriptors, rather the next descriptor - ** is indicated in bits of the descriptor. - ** This also means that we might proceses - ** more than one packet at a time, something - ** that has never been true before, it - ** required eliminating global chain pointers - ** in favor of what we are doing here. -jfv - */ - if (!eop) { - /* - ** Figure out the next descriptor - ** of this frame. - */ - if (rxr->hw_rsc == TRUE) { - rsc = ixgbe_rsc_count(cur); - rxr->rsc_num += (rsc - 1); - } - if (rsc) { /* Get hardware index */ - nextp = ((staterr & - IXGBE_RXDADV_NEXTP_MASK) >> - IXGBE_RXDADV_NEXTP_SHIFT); - } else { /* Just sequential */ - nextp = i + 1; - if (nextp == adapter->num_rx_desc) - nextp = 0; - } - nbuf = &rxr->rx_buffers[nextp]; - prefetch(nbuf); - } - /* - ** The header mbuf is ONLY used when header - ** split is enabled, otherwise we get normal - ** behavior, ie, both header and payload - ** are DMA'd into the payload buffer. - ** - ** Rather than using the fmp/lmp global pointers - ** we now keep the head of a packet chain in the - ** buffer struct and pass this along from one - ** descriptor to the next, until we get EOP. - */ - if (rxr->hdr_split && (rbuf->fmp == NULL)) { - /* This must be an initial descriptor */ - hlen = (hdr & IXGBE_RXDADV_HDRBUFLEN_MASK) >> - IXGBE_RXDADV_HDRBUFLEN_SHIFT; - if (hlen > IXGBE_RX_HDR) - hlen = IXGBE_RX_HDR; - mh->m_len = hlen; - mh->m_flags |= M_PKTHDR; - mh->m_next = NULL; - mh->m_pkthdr.len = mh->m_len; - /* Null buf pointer so it is refreshed */ - rbuf->m_head = NULL; - /* - ** Check the payload length, this - ** could be zero if its a small - ** packet. - */ - if (plen > 0) { - mp->m_len = plen; - mp->m_next = NULL; - mp->m_flags &= ~M_PKTHDR; - mh->m_next = mp; - mh->m_pkthdr.len += mp->m_len; - /* Null buf pointer so it is refreshed */ - rbuf->m_pack = NULL; - rxr->rx_split_packets++; - } - /* - ** Now create the forward - ** chain so when complete - ** we wont have to. - */ - if (eop == 0) { - /* stash the chain head */ - nbuf->fmp = mh; - /* Make forward chain */ - if (plen) - mp->m_next = nbuf->m_pack; - else - mh->m_next = nbuf->m_pack; - } else { - /* Singlet, prepare to send */ - sendmp = mh; - /* If hardware handled vtag */ - if (vtag) { - sendmp->m_pkthdr.ether_vlantag = vtag; - sendmp->m_flags |= M_VLANTAG; - } - } - } else { - /* - ** Either no header split, or a - ** secondary piece of a fragmented - ** split packet. - */ - mp->m_len = plen; - /* - ** See if there is a stored head - ** that determines what we are - */ - sendmp = rbuf->fmp; - rbuf->m_pack = rbuf->fmp = NULL; - - if (sendmp != NULL) { /* secondary frag */ - mp->m_flags &= ~M_PKTHDR; - sendmp->m_pkthdr.len += mp->m_len; - } else { - /* first desc of a non-ps chain */ - sendmp = mp; - sendmp->m_flags |= M_PKTHDR; - sendmp->m_pkthdr.len = mp->m_len; - if (staterr & IXGBE_RXD_STAT_VP) { - sendmp->m_pkthdr.ether_vlantag = vtag; - sendmp->m_flags |= M_VLANTAG; - } - } - /* Pass the head pointer on */ - if (eop == 0) { - nbuf->fmp = sendmp; - sendmp = NULL; - mp->m_next = nbuf->m_pack; - } - } - ++processed; - /* Sending this frame? */ - if (eop) { - sendmp->m_pkthdr.rcvif = ifp; - IFNET_STAT_INC(ifp, ipackets, 1); - rxr->rx_packets++; - /* capture data for AIM */ - rxr->bytes += sendmp->m_pkthdr.len; - rxr->rx_bytes += sendmp->m_pkthdr.len; - if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) - ixgbe_rx_checksum(staterr, sendmp, ptype); -#if 0 /* __FreeBSD_version >= 800000 */ - sendmp->m_pkthdr.flowid = que->msix; - sendmp->m_flags |= M_FLOWID; -#endif - } -next_desc: - bus_dmamap_sync(rxr->rxdma.dma_tag, rxr->rxdma.dma_map, - BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); - - /* Advance our pointers to the next descriptor. */ - if (++i == adapter->num_rx_desc) - i = 0; - - /* Now send to the stack or do LRO */ - if (sendmp != NULL) { - rxr->next_to_check = i; - ixgbe_rx_input(rxr, ifp, sendmp, ptype); - i = rxr->next_to_check; - } - - /* Every 8 descriptors we go to refresh mbufs */ - if (processed == 8) { - ixgbe_refresh_mbufs(rxr, i); - processed = 0; - } - } - - /* Refresh any remaining buf structs */ - if (ixgbe_rx_unrefreshed(rxr)) - ixgbe_refresh_mbufs(rxr, i); - - rxr->next_to_check = i; - - /* - * Flush any outstanding LRO work - */ -#if 0 /* NET_LRO */ - while ((queued = SLIST_FIRST(&lro->lro_active)) != NULL) { - SLIST_REMOVE_HEAD(&lro->lro_active, next); - tcp_lro_flush(lro, queued); - } -#endif - - IXGBE_RX_UNLOCK(rxr); - - /* - ** We still have cleaning to do? - ** Schedule another interrupt if so. - */ - if ((staterr & IXGBE_RXD_STAT_DD) != 0) { - ixgbe_rearm_queues(adapter, (u64)(1 << que->msix)); - } -} - - -/********************************************************************* - * - * 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. - * - *********************************************************************/ -static void -ixgbe_rx_checksum(u32 staterr, struct mbuf * mp, u32 ptype) -{ - u16 status = (u16) staterr; - u8 errors = (u8) (staterr >> 24); - bool sctp = FALSE; - - if ((ptype & IXGBE_RXDADV_PKTTYPE_ETQF) == 0 && - (ptype & IXGBE_RXDADV_PKTTYPE_SCTP) != 0) - sctp = TRUE; - - if (status & IXGBE_RXD_STAT_IPCS) { - if (!(errors & IXGBE_RXD_ERR_IPE)) { - /* IP Checksum Good */ - mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED; - mp->m_pkthdr.csum_flags |= CSUM_IP_VALID; - - } else - mp->m_pkthdr.csum_flags = 0; - } - if (status & IXGBE_RXD_STAT_L4CS) { - u16 type = (CSUM_DATA_VALID | CSUM_PSEUDO_HDR); -#if 0 - if (sctp) - type = CSUM_SCTP_VALID; -#endif - if (!(errors & IXGBE_RXD_ERR_TCPE)) { - mp->m_pkthdr.csum_flags |= type; - if (!sctp) - mp->m_pkthdr.csum_data = htons(0xffff); - } - } - return; -} - - -/* -** This routine is run via an vlan config EVENT, -** it enables us to use the HW Filter table since -** we can get the vlan id. This just creates the -** entry in the soft version of the VFTA, init will -** repopulate the real table. -*/ -static void -ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) -{ - struct adapter *adapter = ifp->if_softc; - u16 index, bit; - - if (ifp->if_softc != arg) /* Not our event */ - return; - - if ((vtag == 0) || (vtag > 4095)) /* Invalid */ - return; - - IXGBE_CORE_LOCK(adapter); - index = (vtag >> 5) & 0x7F; - bit = vtag & 0x1F; - adapter->shadow_vfta[index] |= (1 << bit); - ++adapter->num_vlans; - ixgbe_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); -} - -/* -** This routine is run via an vlan -** unconfig EVENT, remove our entry -** in the soft vfta. -*/ -static void -ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) -{ - struct adapter *adapter = ifp->if_softc; - u16 index, bit; - - if (ifp->if_softc != arg) - return; - - if ((vtag == 0) || (vtag > 4095)) /* Invalid */ - return; - - IXGBE_CORE_LOCK(adapter); - index = (vtag >> 5) & 0x7F; - bit = vtag & 0x1F; - adapter->shadow_vfta[index] &= ~(1 << bit); - --adapter->num_vlans; - /* Re-init to load the changes */ - ixgbe_init_locked(adapter); - IXGBE_CORE_UNLOCK(adapter); -} - -static void -ixgbe_setup_vlan_hw_support(struct adapter *adapter) -{ - struct ifnet *ifp = adapter->ifp; - struct ixgbe_hw *hw = &adapter->hw; - struct rx_ring *rxr; - u32 ctrl; - - /* - ** We get here thru init_locked, meaning - ** a soft reset, this has already cleared - ** the VFTA and other state, so if there - ** have been no vlan's registered do nothing. - */ - if (adapter->num_vlans == 0) - return; - - /* - ** A soft reset zero's out the VFTA, so - ** we need to repopulate it now. - */ - for (int i = 0; i < IXGBE_VFTA_SIZE; i++) - if (adapter->shadow_vfta[i] != 0) - IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), - adapter->shadow_vfta[i]); - - ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); - /* Enable the Filter Table if enabled */ - if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { - ctrl &= ~IXGBE_VLNCTRL_CFIEN; - ctrl |= IXGBE_VLNCTRL_VFE; - } - if (hw->mac.type == ixgbe_mac_82598EB) - ctrl |= IXGBE_VLNCTRL_VME; - IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); - - /* Setup the queues for vlans */ - for (int i = 0; i < adapter->num_queues; i++) { - rxr = &adapter->rx_rings[i]; - /* On 82599 the VLAN enable is per/queue in RXDCTL */ - if (hw->mac.type != ixgbe_mac_82598EB) { - ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); - ctrl |= IXGBE_RXDCTL_VME; - IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl); - } - rxr->vtag_strip = TRUE; - } -} - -static void -ixgbe_enable_intr(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - struct ix_queue *que = adapter->queues; - u32 mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); - - - /* Enable Fan Failure detection */ - if (hw->device_id == IXGBE_DEV_ID_82598AT) - mask |= IXGBE_EIMS_GPI_SDP1; - else { - mask |= IXGBE_EIMS_ECC; - mask |= IXGBE_EIMS_GPI_SDP0; - mask |= IXGBE_EIMS_GPI_SDP1; - mask |= IXGBE_EIMS_GPI_SDP2; -#ifdef IXGBE_FDIR - mask |= IXGBE_EIMS_FLOW_DIR; -#endif - } - - IXGBE_WRITE_REG(hw, IXGBE_EIMS, mask); - - /* With RSS we use auto clear */ - if (adapter->msix_mem) { - mask = IXGBE_EIMS_ENABLE_MASK; - /* Don't autoclear Link */ - mask &= ~IXGBE_EIMS_OTHER; - mask &= ~IXGBE_EIMS_LSC; - IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); - } - - /* - ** Now enable all queues, this is done separately to - ** allow for handling the extended (beyond 32) MSIX - ** vectors that can be used by 82599 - */ - for (int i = 0; i < adapter->num_queues; i++, que++) - ixgbe_enable_queue(adapter, que->msix); - - IXGBE_WRITE_FLUSH(hw); - - return; -} - -static void -ixgbe_disable_intr(struct adapter *adapter) -{ - if (adapter->msix_mem) - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC, 0); - if (adapter->hw.mac.type == ixgbe_mac_82598EB) { - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0); - } else { - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0); - } - IXGBE_WRITE_FLUSH(&adapter->hw); - return; -} - -u16 -ixgbe_read_pci_cfg(struct ixgbe_hw *hw, u32 reg) -{ - u16 value; - - value = pci_read_config(((struct ixgbe_osdep *)hw->back)->dev, - reg, 2); - - return (value); -} - -void -ixgbe_write_pci_cfg(struct ixgbe_hw *hw, u32 reg, u16 value) -{ - pci_write_config(((struct ixgbe_osdep *)hw->back)->dev, - reg, value, 2); - - return; -} - -/* -** Setup the correct IVAR register for a particular MSIX interrupt -** (yes this is all very magic and confusing :) -** - entry is the register array entry -** - vector is the MSIX vector for this queue -** - type is RX/TX/MISC -*/ -static void -ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) -{ - struct ixgbe_hw *hw = &adapter->hw; - u32 ivar, index; - - vector |= IXGBE_IVAR_ALLOC_VAL; - - switch (hw->mac.type) { - - case ixgbe_mac_82598EB: - if (type == -1) - entry = IXGBE_IVAR_OTHER_CAUSES_INDEX; - else - entry += (type * 64); - index = (entry >> 2) & 0x1F; - ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index)); - ivar &= ~(0xFF << (8 * (entry & 0x3))); - ivar |= (vector << (8 * (entry & 0x3))); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar); - break; - - case ixgbe_mac_82599EB: - case ixgbe_mac_X540: - if (type == -1) { /* MISC IVAR */ - index = (entry & 1) * 8; - ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); - ivar &= ~(0xFF << index); - ivar |= (vector << index); - IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); - } else { /* RX/TX IVARS */ - index = (16 * (entry & 1)) + (8 * type); - ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); - ivar &= ~(0xFF << index); - ivar |= (vector << index); - IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar); - } - - default: - break; - } -} - -static void -ixgbe_configure_ivars(struct adapter *adapter) -{ - struct ix_queue *que = adapter->queues; - - for (int i = 0; i < adapter->num_queues; i++, que++) { - /* First the RX queue entry */ - ixgbe_set_ivar(adapter, i, que->msix, 0); - /* ... and the TX */ - ixgbe_set_ivar(adapter, i, que->msix, 1); - /* Set an Initial EITR value */ - ixgbe_set_eitr(adapter, que->msix, IXGBE_INTR_RATE); - } - - /* For the Link interrupt */ - ixgbe_set_ivar(adapter, 1, adapter->linkvec, -1); -} - -/* -** ixgbe_sfp_probe - called in the local timer to -** determine if a port had optics inserted. -*/ -static bool ixgbe_sfp_probe(struct adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - device_t dev = adapter->dev; - bool result = FALSE; - - if ((hw->phy.type == ixgbe_phy_nl) && - (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { - s32 ret = hw->phy.ops.identify_sfp(hw); - if (ret) - goto out; - ret = hw->phy.ops.reset(hw); - if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { - device_printf(dev,"Unsupported SFP+ module detected!"); - kprintf(" Reload driver with supported module.\n"); - adapter->sfp_probe = FALSE; - goto out; - } else - device_printf(dev,"SFP+ module detected!\n"); - /* We now have supported optics */ - adapter->sfp_probe = FALSE; - /* Set the optics type so system reports correctly */ - ixgbe_setup_optics(adapter); - result = TRUE; - } -out: - return (result); -} - -/* -** Tasklet for handling SFP module interrupts -*/ -static void -ixgbe_handle_mod(void *context, int pending) -{ - struct adapter *adapter = context; - struct ixgbe_hw *hw = &adapter->hw; - device_t dev = adapter->dev; - u32 err; - - err = hw->phy.ops.identify_sfp(hw); - if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - device_printf(dev, - "Unsupported SFP+ module type was detected.\n"); - return; - } - err = hw->mac.ops.setup_sfp(hw); - if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - device_printf(dev, - "Setup failure - unsupported SFP+ module type.\n"); - return; - } - taskqueue_enqueue(adapter->tq, &adapter->msf_task); - return; -} - - -/* -** Tasklet for handling MSF (multispeed fiber) interrupts -*/ -static void -ixgbe_handle_msf(void *context, int pending) -{ - struct adapter *adapter = context; - struct ixgbe_hw *hw = &adapter->hw; - u32 autoneg; - bool negotiate; - - autoneg = hw->phy.autoneg_advertised; - if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) - hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate); - if (hw->mac.ops.setup_link) - hw->mac.ops.setup_link(hw, autoneg, negotiate, TRUE); - return; -} - -#ifdef IXGBE_FDIR -/* -** Tasklet for reinitializing the Flow Director filter table -*/ -static void -ixgbe_reinit_fdir(void *context, int pending) -{ - struct adapter *adapter = context; - struct ifnet *ifp = adapter->ifp; - - if (adapter->fdir_reinit != 1) /* Shouldn't happen */ - return; - ixgbe_reinit_fdir_tables_82599(&adapter->hw); - adapter->fdir_reinit = 0; - /* re-enable flow director interrupts */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); - /* Restart the interface */ - ifp->if_drv_flags |= IFF_DRV_RUNNING; - return; -} -#endif - -/********************************************************************** - * - * Update the board statistics counters. - * - **********************************************************************/ -static void -ixgbe_update_stats_counters(struct adapter *adapter) -{ - struct ifnet *ifp = adapter->ifp; - struct ixgbe_hw *hw = &adapter->hw; - u32 missed_rx = 0, bprc, lxon, lxoff, total; - u64 total_missed_rx = 0; - - adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); - adapter->stats.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); - adapter->stats.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); - adapter->stats.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); - - for (int i = 0; i < 8; i++) { - u32 mp; - mp = IXGBE_READ_REG(hw, IXGBE_MPC(i)); - /* missed_rx tallies misses for the gprc workaround */ - missed_rx += mp; - /* global total per queue */ - adapter->stats.mpc[i] += mp; - /* Running comprehensive total for stats display */ - total_missed_rx += adapter->stats.mpc[i]; - if (hw->mac.type == ixgbe_mac_82598EB) - adapter->stats.rnbc[i] += - IXGBE_READ_REG(hw, IXGBE_RNBC(i)); - adapter->stats.pxontxc[i] += - IXGBE_READ_REG(hw, IXGBE_PXONTXC(i)); - adapter->stats.pxonrxc[i] += - IXGBE_READ_REG(hw, IXGBE_PXONRXC(i)); - adapter->stats.pxofftxc[i] += - IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i)); - adapter->stats.pxoffrxc[i] += - IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i)); - adapter->stats.pxon2offc[i] += - IXGBE_READ_REG(hw, IXGBE_PXON2OFFCNT(i)); - } - for (int i = 0; i < 16; i++) { - adapter->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); - adapter->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); - adapter->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i)); - adapter->stats.qbrc[i] += - ((u64)IXGBE_READ_REG(hw, IXGBE_QBRC(i)) << 32); - adapter->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i)); - adapter->stats.qbtc[i] += - ((u64)IXGBE_READ_REG(hw, IXGBE_QBTC(i)) << 32); - adapter->stats.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i)); - } - adapter->stats.mlfc += IXGBE_READ_REG(hw, IXGBE_MLFC); - adapter->stats.mrfc += IXGBE_READ_REG(hw, IXGBE_MRFC); - adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC); - - /* Hardware workaround, gprc counts missed packets */ - adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); - adapter->stats.gprc -= missed_rx; - - if (hw->mac.type != ixgbe_mac_82598EB) { - adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + - ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); - adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + - ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); - adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORL) + - ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); - adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); - adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); - } else { - adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC); - adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC); - /* 82598 only has a counter in the high register */ - adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH); - adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); - adapter->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); - adapter->stats.bprc += bprc; - adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC); - if (hw->mac.type == ixgbe_mac_82598EB) - adapter->stats.mprc -= bprc; - - adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64); - adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127); - adapter->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255); - adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511); - adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023); - adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522); - - lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC); - adapter->stats.lxontxc += lxon; - lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC); - adapter->stats.lxofftxc += lxoff; - total = lxon + lxoff; - - adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC); - adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC); - adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64); - adapter->stats.gptc -= total; - adapter->stats.mptc -= total; - adapter->stats.ptc64 -= total; - adapter->stats.gotc -= total * ETHER_MIN_LEN; - - adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC); - adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC); - adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC); - adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC); - adapter->stats.mngprc += IXGBE_READ_REG(hw, IXGBE_MNGPRC); - adapter->stats.mngpdc += IXGBE_READ_REG(hw, IXGBE_MNGPDC); - adapter->stats.mngptc += IXGBE_READ_REG(hw, IXGBE_MNGPTC); - adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR); - adapter->stats.tpt += IXGBE_READ_REG(hw, IXGBE_TPT); - adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127); - adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255); - adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511); - adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023); - adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522); - adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC); - adapter->stats.xec += IXGBE_READ_REG(hw, IXGBE_XEC); - adapter->stats.fccrc += IXGBE_READ_REG(hw, IXGBE_FCCRC); - adapter->stats.fclast += IXGBE_READ_REG(hw, IXGBE_FCLAST); - /* Only read FCOE on 82599 */ - if (hw->mac.type != ixgbe_mac_82598EB) { - adapter->stats.fcoerpdc += IXGBE_READ_REG(hw, IXGBE_FCOERPDC); - adapter->stats.fcoeprc += IXGBE_READ_REG(hw, IXGBE_FCOEPRC); - adapter->stats.fcoeptc += IXGBE_READ_REG(hw, IXGBE_FCOEPTC); - adapter->stats.fcoedwrc += IXGBE_READ_REG(hw, IXGBE_FCOEDWRC); - adapter->stats.fcoedwtc += IXGBE_READ_REG(hw, IXGBE_FCOEDWTC); - } - - /* Fill out the OS statistics structure */ - IFNET_STAT_SET(ifp, ipackets, adapter->stats.gprc); - IFNET_STAT_SET(ifp, opackets, adapter->stats.gptc); - IFNET_STAT_SET(ifp, ibytes, adapter->stats.gorc); - IFNET_STAT_SET(ifp, obytes, adapter->stats.gotc); - IFNET_STAT_SET(ifp, imcasts, adapter->stats.mprc); - - /* Rx Errors */ - IFNET_STAT_SET(ifp, ierrors, total_missed_rx + adapter->stats.crcerrs + - adapter->stats.rlec); -} - -/** ixgbe_sysctl_tdh_handler - Handler function - * Retrieves the TDH value from the hardware - */ -static int -ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) -{ - int error; - - struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); - if (!txr) return 0; - - unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} - -/** ixgbe_sysctl_tdt_handler - Handler function - * Retrieves the TDT value from the hardware - */ -static int -ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) -{ - int error; - - struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); - if (!txr) return 0; - - unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} - -/** ixgbe_sysctl_rdh_handler - Handler function - * Retrieves the RDH value from the hardware - */ -static int -ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) -{ - int error; - - struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); - if (!rxr) return 0; - - unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} - -/** ixgbe_sysctl_rdt_handler - Handler function - * Retrieves the RDT value from the hardware - */ -static int -ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) -{ - int error; - - struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); - if (!rxr) return 0; - - unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); - error = sysctl_handle_int(oidp, &val, 0, req); - if (error || !req->newptr) - return error; - return 0; -} - -/* - * Add sysctl variables, one per statistic, to the system. - */ -static void -ixgbe_add_hw_stats(struct adapter *adapter) -{ - struct tx_ring *txr = adapter->tx_rings; - struct rx_ring *rxr = adapter->rx_rings; - - struct sysctl_ctx_list *ctx = &adapter->sysctl_ctx; - struct sysctl_oid *tree = adapter->sysctl_tree; - struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); - struct ixgbe_hw_stats *stats = &adapter->stats; - - struct sysctl_oid *stat_node, *queue_node; - struct sysctl_oid_list *stat_list, *queue_list; - -#define QUEUE_NAME_LEN 32 - char namebuf[QUEUE_NAME_LEN]; - - /* Driver Statistics */ - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", - CTLFLAG_RD, &adapter->dropped_pkts, - "Driver dropped packets"); - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", - CTLFLAG_RD, &adapter->mbuf_defrag_failed, - "m_defrag() failed"); - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "no_tx_dma_setup", - CTLFLAG_RD, &adapter->no_tx_dma_setup, - "Driver tx dma failure in xmit"); - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", - CTLFLAG_RD, &adapter->watchdog_events, - "Watchdog timeouts"); - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "tso_tx", - CTLFLAG_RD, &adapter->tso_tx, - "TSO"); - SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", - CTLFLAG_RD, &adapter->link_irq, - "Link MSIX IRQ Handled"); - - for (int i = 0; i < adapter->num_queues; i++, txr++) { - ksnprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); - queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "Queue Name"); - queue_list = SYSCTL_CHILDREN(queue_node); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", - CTLFLAG_RD, &(adapter->queues[i].irqs), 0, - "irqs on this queue"); - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", - CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), - ixgbe_sysctl_tdh_handler, "IU", - "Transmit Descriptor Head"); - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", - CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), - ixgbe_sysctl_tdt_handler, "IU", - "Transmit Descriptor Tail"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", - CTLFLAG_RD, &txr->no_desc_avail, 0, - "Queue No Descriptor Available"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", - CTLFLAG_RD, &txr->total_packets, 0, - "Queue Packets Transmitted"); - } - - for (int i = 0; i < adapter->num_queues; i++, rxr++) { - ksnprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); - queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "Queue Name"); - queue_list = SYSCTL_CHILDREN(queue_node); - -#if 0 /* NET_LRO */ - struct lro_ctrl *lro = &rxr->lro; -#endif - - ksnprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); - queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "Queue Name"); - queue_list = SYSCTL_CHILDREN(queue_node); - - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", - CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), - ixgbe_sysctl_rdh_handler, "IU", - "Receive Descriptor Head"); - SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", - CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), - ixgbe_sysctl_rdt_handler, "IU", - "Receive Descriptor Tail"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", - CTLFLAG_RD, &rxr->rx_packets, 0, - "Queue Packets Received"); - SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", - CTLFLAG_RD, &rxr->rx_bytes, 0, - "Queue Bytes Received"); -#if 0 /* NET_LRO */ - SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_queued", - CTLFLAG_RD, &lro->lro_queued, 0, - "LRO Queued"); - SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "lro_flushed", - CTLFLAG_RD, &lro->lro_flushed, 0, - "LRO Flushed"); -#endif - } - - /* MAC stats get the own sub node */ - - stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", - CTLFLAG_RD, NULL, "MAC Statistics"); - stat_list = SYSCTL_CHILDREN(stat_node); - - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", - CTLFLAG_RD, &stats->crcerrs, 0, - "CRC Errors"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", - CTLFLAG_RD, &stats->illerrc, 0, - "Illegal Byte Errors"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", - CTLFLAG_RD, &stats->errbc, 0, - "Byte Errors"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", - CTLFLAG_RD, &stats->mspdc, 0, - "MAC Short Packets Discarded"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", - CTLFLAG_RD, &stats->mlfc, 0, - "MAC Local Faults"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", - CTLFLAG_RD, &stats->mrfc, 0, - "MAC Remote Faults"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", - CTLFLAG_RD, &stats->rlec, 0, - "Receive Length Errors"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "link_xon_txd", - CTLFLAG_RD, &stats->lxontxc, 0, - "Link XON Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "link_xon_rcvd", - CTLFLAG_RD, &stats->lxonrxc, 0, - "Link XON Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "link_xoff_txd", - CTLFLAG_RD, &stats->lxofftxc, 0, - "Link XOFF Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "link_xoff_rcvd", - CTLFLAG_RD, &stats->lxoffrxc, 0, - "Link XOFF Received"); - - /* Packet Reception Stats */ - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", - CTLFLAG_RD, &stats->tor, 0, - "Total Octets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", - CTLFLAG_RD, &stats->gorc, 0, - "Good Octets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", - CTLFLAG_RD, &stats->tpr, 0, - "Total Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", - CTLFLAG_RD, &stats->gprc, 0, - "Good Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", - CTLFLAG_RD, &stats->mprc, 0, - "Multicast Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", - CTLFLAG_RD, &stats->bprc, 0, - "Broadcast Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", - CTLFLAG_RD, &stats->prc64, 0, - "64 byte frames received "); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", - CTLFLAG_RD, &stats->prc127, 0, - "65-127 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", - CTLFLAG_RD, &stats->prc255, 0, - "128-255 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", - CTLFLAG_RD, &stats->prc511, 0, - "256-511 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", - CTLFLAG_RD, &stats->prc1023, 0, - "512-1023 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", - CTLFLAG_RD, &stats->prc1522, 0, - "1023-1522 byte frames received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", - CTLFLAG_RD, &stats->ruc, 0, - "Receive Undersized"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", - CTLFLAG_RD, &stats->rfc, 0, - "Fragmented Packets Received "); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", - CTLFLAG_RD, &stats->roc, 0, - "Oversized Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", - CTLFLAG_RD, &stats->rjc, 0, - "Received Jabber"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", - CTLFLAG_RD, &stats->mngprc, 0, - "Management Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", - CTLFLAG_RD, &stats->mngptc, 0, - "Management Packets Dropped"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", - CTLFLAG_RD, &stats->xec, 0, - "Checksum Errors"); - - /* Packet Transmission Stats */ - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", - CTLFLAG_RD, &stats->gotc, 0, - "Good Octets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", - CTLFLAG_RD, &stats->tpt, 0, - "Total Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", - CTLFLAG_RD, &stats->gptc, 0, - "Good Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", - CTLFLAG_RD, &stats->bptc, 0, - "Broadcast Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", - CTLFLAG_RD, &stats->mptc, 0, - "Multicast Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", - CTLFLAG_RD, &stats->mngptc, 0, - "Management Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", - CTLFLAG_RD, &stats->ptc64, 0, - "64 byte frames transmitted "); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", - CTLFLAG_RD, &stats->ptc127, 0, - "65-127 byte frames transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", - CTLFLAG_RD, &stats->ptc255, 0, - "128-255 byte frames transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", - CTLFLAG_RD, &stats->ptc511, 0, - "256-511 byte frames transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", - CTLFLAG_RD, &stats->ptc1023, 0, - "512-1023 byte frames transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", - CTLFLAG_RD, &stats->ptc1522, 0, - "1024-1522 byte frames transmitted"); - - /* FC Stats */ - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fc_crc", - CTLFLAG_RD, &stats->fccrc, 0, - "FC CRC Errors"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fc_last", - CTLFLAG_RD, &stats->fclast, 0, - "FC Last Error"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fc_drpd", - CTLFLAG_RD, &stats->fcoerpdc, 0, - "FCoE Packets Dropped"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fc_pkts_rcvd", - CTLFLAG_RD, &stats->fcoeprc, 0, - "FCoE Packets Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fc_pkts_txd", - CTLFLAG_RD, &stats->fcoeptc, 0, - "FCoE Packets Transmitted"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fc_dword_rcvd", - CTLFLAG_RD, &stats->fcoedwrc, 0, - "FCoE DWords Received"); - SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "fc_dword_txd", - CTLFLAG_RD, &stats->fcoedwtc, 0, - "FCoE DWords Transmitted"); -} - -/* -** Set flow control using sysctl: -** Flow control values: -** 0 - off -** 1 - rx pause -** 2 - tx pause -** 3 - full -*/ -static int -ixgbe_set_flowcntl(SYSCTL_HANDLER_ARGS) -{ - int error, last; - struct adapter *adapter = (struct adapter *) arg1; - - last = adapter->fc; - error = sysctl_handle_int(oidp, &adapter->fc, 0, req); - if ((error) || (req->newptr == NULL)) - return (error); - - /* Don't bother if it's not changed */ - if (adapter->fc == last) - return (0); - - switch (adapter->fc) { - case ixgbe_fc_rx_pause: - case ixgbe_fc_tx_pause: - case ixgbe_fc_full: - adapter->hw.fc.requested_mode = adapter->fc; - break; - case ixgbe_fc_none: - default: - adapter->hw.fc.requested_mode = ixgbe_fc_none; - } - /* Don't autoneg if forcing a value */ - adapter->hw.fc.disable_fc_autoneg = TRUE; - ixgbe_fc_enable(&adapter->hw); - return error; -} - -static void -ixgbe_add_rx_process_limit(struct adapter *adapter, const char *name, - const char *description, int *limit, int value) -{ - *limit = value; - SYSCTL_ADD_INT(&adapter->sysctl_ctx, - SYSCTL_CHILDREN(adapter->sysctl_tree), - OID_AUTO, name, CTLTYPE_INT|CTLFLAG_RW, limit, value, description); -} - -/* -** Control link advertise speed: -** 1 - advertise only 1G -** 2 - advertise 100Mb -** 3 - advertise normal -*/ -static int -ixgbe_set_advertise(SYSCTL_HANDLER_ARGS) -{ - int error = 0; - struct adapter *adapter; - device_t dev; - struct ixgbe_hw *hw; - ixgbe_link_speed speed, last; - - adapter = (struct adapter *) arg1; - dev = adapter->dev; - hw = &adapter->hw; - last = adapter->advertise; - - error = sysctl_handle_int(oidp, &adapter->advertise, 0, req); - if ((error) || (adapter->advertise == -1)) - return (error); - - if (adapter->advertise == last) /* no change */ - return (0); - - if (!((hw->phy.media_type == ixgbe_media_type_copper) || - (hw->phy.multispeed_fiber))) - return (error); - - if ((adapter->advertise == 2) && (hw->mac.type != ixgbe_mac_X540)) { - device_printf(dev, "Set Advertise: 100Mb on X540 only\n"); - return (error); - } - - if (adapter->advertise == 1) - speed = IXGBE_LINK_SPEED_1GB_FULL; - else if (adapter->advertise == 2) - speed = IXGBE_LINK_SPEED_100_FULL; - else if (adapter->advertise == 3) - speed = IXGBE_LINK_SPEED_1GB_FULL | - IXGBE_LINK_SPEED_10GB_FULL; - else /* bogus value */ - return (error); - - hw->mac.autotry_restart = TRUE; - hw->mac.ops.setup_link(hw, speed, TRUE, TRUE); - - return (error); -} - -/* -** Thermal Shutdown Trigger -** - cause a Thermal Overtemp IRQ -*/ -static int -ixgbe_set_thermal_test(SYSCTL_HANDLER_ARGS) -{ - int error, fire = 0; - struct adapter *adapter = (struct adapter *) arg1; - struct ixgbe_hw *hw = &adapter->hw; - - - if (hw->mac.type != ixgbe_mac_X540) - return (0); - - error = sysctl_handle_int(oidp, &fire, 0, req); - if ((error) || (req->newptr == NULL)) - return (error); - - if (fire) { - u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS); - reg |= IXGBE_EICR_TS; - IXGBE_WRITE_REG(hw, IXGBE_EICS, reg); - } - - return (0); -} - -static void -ixgbe_set_eitr(struct adapter *sc, int idx, int rate) -{ - uint32_t eitr = 0; - - /* convert rate in intr/s to hw representation */ - if (rate > 0) { - eitr = 1000000 / rate; - eitr <<= IXGBE_EITR_INTVL_SHIFT; - - if (eitr == 0) { - /* Don't disable it */ - eitr = 1 << IXGBE_EITR_INTVL_SHIFT; - } else if (eitr > IXGBE_EITR_INTVL_MASK) { - /* Don't allow it to be too large */ - eitr = IXGBE_EITR_INTVL_MASK; - } - } - IXGBE_WRITE_REG(&sc->hw, IXGBE_EITR(idx), eitr); -} - -static int -ixgbe_sysctl_intr_rate(SYSCTL_HANDLER_ARGS) -{ - struct adapter *sc = (void *)arg1; - struct ifnet *ifp = sc->ifp; - int error, intr_rate, running; - struct ix_queue *que = sc->queues; - - intr_rate = sc->intr_rate; - error = sysctl_handle_int(oidp, &intr_rate, 0, req); - if (error || req->newptr == NULL) - return error; - if (intr_rate < 0) - return EINVAL; - - ifnet_serialize_all(ifp); - - sc->intr_rate = intr_rate; - running = ifp->if_flags & IFF_RUNNING; - if (running) - ixgbe_set_eitr(sc, 0, sc->intr_rate); - - if (running && (sc->intr_type == PCI_INTR_TYPE_MSIX)) { - for (int i = 0; i < sc->num_queues; i++, que++) - ixgbe_set_eitr(sc, que->msix, sc->intr_rate); - } - - if (bootverbose) - if_printf(ifp, "interrupt rate set to %d/sec\n", sc->intr_rate); - - ifnet_deserialize_all(ifp); - - return 0; -} - -/* rearrange mbuf chain to get contiguous bytes */ -static int -ixgbe_tso_pullup(struct tx_ring *txr, struct mbuf **mp) -{ - int hoff, iphlen, thoff; - struct mbuf *m; - - m = *mp; - KASSERT(M_WRITABLE(m), ("TSO mbuf not writable")); - - iphlen = m->m_pkthdr.csum_iphlen; - thoff = m->m_pkthdr.csum_thlen; - hoff = m->m_pkthdr.csum_lhlen; - - KASSERT(iphlen > 0, ("invalid ip hlen")); - KASSERT(thoff > 0, ("invalid tcp hlen")); - KASSERT(hoff > 0, ("invalid ether hlen")); - - if (__predict_false(m->m_len < hoff + iphlen + thoff)) { - m = m_pullup(m, hoff + iphlen + thoff); - if (m == NULL) { - *mp = NULL; - return ENOBUFS; - } - *mp = m; - } - - return 0; -} diff --git a/sys/dev/netif/ixgbe/ixgbe.h b/sys/dev/netif/ixgbe/ixgbe.h deleted file mode 100644 index b225f8a799..0000000000 --- a/sys/dev/netif/ixgbe/ixgbe.h +++ /dev/null @@ -1,513 +0,0 @@ -/****************************************************************************** - - Copyright (c) 2001-2012, 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.26 2012/04/23 22:05:09 bz Exp $*/ - - -#ifndef _IXGBE_H_ -#define _IXGBE_H_ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#ifdef NET_LRO -#include /* XXX: IPv4 only */ -#endif -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef IXGBE_IEEE1588 -#include -#endif - -#include "ixgbe_api.h" -#include "ixgbe_defines.h" - -/* 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 1024 -#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 1024 -#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_LOOP 10 - -/* - * This is the max watchdog interval, ie. the time that can - * pass between any two TX clean operations, such only happening - * when the TX hardware is functioning. - */ -#define IXGBE_WATCHDOG (10 * hz) - -/* - * This parameters control when the driver calls the routine to reclaim - * transmit descriptors. - */ -#define IXGBE_TX_CLEANUP_THRESHOLD (adapter->num_tx_desc / 8) -#define IXGBE_TX_OP_THRESHOLD (adapter->num_tx_desc / 32) - -#define IXGBE_MAX_FRAME_SIZE 0x3F00 - -/* Flow control constants */ -#define IXGBE_FC_PAUSE 0xFFFF -#define IXGBE_FC_HI 0x20000 -#define IXGBE_FC_LO 0x10000 - -/* Keep older OS drivers building... */ -#if !defined(SYSCTL_ADD_UQUAD) -#define SYSCTL_ADD_UQUAD SYSCTL_ADD_QUAD -#endif - -/* Defines for printing debug information */ -#define DEBUG_INIT 0 -#define DEBUG_IOCTL 0 -#define DEBUG_HW 0 - -#define INIT_DEBUGOUT(S) if (DEBUG_INIT) kprintf(S "\n") -#define INIT_DEBUGOUT1(S, A) if (DEBUG_INIT) kprintf(S "\n", A) -#define INIT_DEBUGOUT2(S, A, B) if (DEBUG_INIT) kprintf(S "\n", A, B) -#define IOCTL_DEBUGOUT(S) if (DEBUG_IOCTL) kprintf(S "\n") -#define IOCTL_DEBUGOUT1(S, A) if (DEBUG_IOCTL) kprintf(S "\n", A) -#define IOCTL_DEBUGOUT2(S, A, B) if (DEBUG_IOCTL) kprintf(S "\n", A, B) -#define HW_DEBUGOUT(S) if (DEBUG_HW) kprintf(S "\n") -#define HW_DEBUGOUT1(S, A) if (DEBUG_HW) kprintf(S "\n", A) -#define HW_DEBUGOUT2(S, A, B) if (DEBUG_HW) kprintf(S "\n", A, B) - -#define MAX_NUM_MULTICAST_ADDRESSES 128 -#define IXGBE_82598_SCATTER 100 -#define IXGBE_82599_SCATTER 32 -#define MSIX_82598_BAR 3 -#define MSIX_82599_BAR 4 -#define IXGBE_TSO_SIZE 262140 -#define IXGBE_TX_BUFFER_SIZE ((u32) 1514) -#define IXGBE_RX_HDR 128 -#define IXGBE_VFTA_SIZE 128 -#define IXGBE_BR_SIZE 4096 -#define IXGBE_QUEUE_MIN_FREE 32 -#define IXGBE_QUEUE_IDLE 1 -#define IXGBE_QUEUE_WORKING 2 -#define IXGBE_QUEUE_HUNG 4 -#define IXGBE_QUEUE_DEPLETED 8 - -/* Offload bits in mbuf flag */ -#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP) - -/* One for TX csum offloading desc, the other 2 are reserved */ -#define IXGBE_TX_RESERVED 3 - -/* - * Interrupt Moderation parameters - */ -#define IXGBE_LOW_LATENCY 128 -#define IXGBE_AVE_LATENCY 400 -#define IXGBE_BULK_LATENCY 1200 -#define IXGBE_LINK_ITR 2000 - -#define IXGBE_INTR_RATE 8000 -#define IXGBE_EITR_INTVL_MASK 0x7ffc -#define IXGBE_EITR_INTVL_SHIFT 2 - -/* - ***************************************************************************** - * vendor_info_array - * - * This array contains the list of Subvendor/Subdevice IDs on which the driver - * should load. - * - ***************************************************************************** - */ -typedef struct _ixgbe_vendor_info_t { - unsigned int vendor_id; - unsigned int device_id; - unsigned int subvendor_id; - unsigned int subdevice_id; - unsigned int index; -} ixgbe_vendor_info_t; - - -struct ixgbe_tx_buf { - u32 eop_index; - struct mbuf *m_head; - bus_dmamap_t map; -}; - -struct ixgbe_rx_buf { - struct mbuf *m_head; - struct mbuf *m_pack; - struct mbuf *fmp; - bus_dmamap_t hmap; - bus_dmamap_t pmap; -}; - -/* - * Bus dma allocation structure used by ixgbe_dma_malloc and ixgbe_dma_free. - */ -struct ixgbe_dma_alloc { - bus_addr_t dma_paddr; - 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; -}; - -/* -** Driver queue struct: this is the interrupt container -** for the associated tx and rx ring. -*/ -struct ix_queue { - struct adapter *adapter; - u32 msix; /* This queue's MSIX vector */ - u32 eims; /* This queue's EIMS bit */ - u32 eitr_setting; - struct resource *res; - void *tag; - struct tx_ring *txr; - struct rx_ring *rxr; - u64 irqs; - struct lwkt_serialize serializer; -}; - -/* - * The transmit ring, one per queue - */ -struct tx_ring { - struct adapter *adapter; - struct lwkt_serialize tx_serialize; - u32 me; - int queue_status; - int watchdog_time; - union ixgbe_adv_tx_desc *tx_base; - struct ixgbe_dma_alloc txdma; - u32 next_avail_desc; - u32 next_to_clean; - struct ixgbe_tx_buf *tx_buffers; - volatile u16 tx_avail; - u32 txd_cmd; - bus_dma_tag_t txtag; - char lock_name[16]; -#ifdef IFNET_BUF_RING - struct buf_ring *br; -#endif -#ifdef IXGBE_FDIR - u16 atr_sample; - u16 atr_count; -#endif - u32 bytes; /* used for AIM */ - u32 packets; - /* Soft Stats */ - u64 no_desc_avail; - u64 total_packets; -}; - - -/* - * The Receive ring, one per rx queue - */ -struct rx_ring { - struct adapter *adapter; - struct lock rx_lock; - u32 me; - union ixgbe_adv_rx_desc *rx_base; - struct ixgbe_dma_alloc rxdma; -#ifdef NET_LRO - struct lro_ctrl lro; -#endif - bool lro_enabled; - bool hdr_split; - bool hw_rsc; - bool discard; - bool vtag_strip; - u32 next_to_refresh; - u32 next_to_check; - char lock_name[16]; - struct ixgbe_rx_buf *rx_buffers; - bus_dma_tag_t htag; - bus_dma_tag_t ptag; - - u32 bytes; /* Used for AIM calc */ - u32 packets; - - /* Soft stats */ - u64 rx_irq; - u64 rx_split_packets; - u64 rx_packets; - u64 rx_bytes; - u64 rx_discarded; - u64 rsc_num; -#ifdef IXGBE_FDIR - u64 flm; -#endif -}; - -/* Our adapter structure */ -struct adapter { - struct ifnet *ifp; - struct ixgbe_hw hw; - - struct ixgbe_osdep osdep; - struct device *dev; - - struct resource *pci_mem; - struct resource *msix_mem; - - /* - * Interrupt resources: this set is - * either used for legacy, or for Link - * when doing MSIX - */ - void *tag; - struct resource *res; - int intr_type; - - struct ifmedia media; - struct callout timer; - int msix; - int if_flags; - - struct lock core_lock; - - eventhandler_tag vlan_attach; - eventhandler_tag vlan_detach; - - u16 num_vlans; - u16 num_queues; - - /* - ** Shadow VFTA table, this is needed because - ** the real vlan filter table gets cleared during - ** a soft reset and the driver needs to be able - ** to repopulate it. - */ - u32 shadow_vfta[IXGBE_VFTA_SIZE]; - - /* Info about the interface */ - u32 optics; - u32 fc; /* local flow ctrl setting */ - int advertise; /* link speeds */ - bool link_active; - u16 max_frame_size; - u16 num_segs; - u32 link_speed; - bool link_up; - u32 linkvec; - - /* Mbuf cluster size */ - u32 rx_mbuf_sz; - - /* Support for pluggable optics */ - bool sfp_probe; - struct task mod_task; /* SFP tasklet */ - struct task msf_task; /* Multispeed Fiber */ -#ifdef IXGBE_FDIR - int fdir_reinit; - struct task fdir_task; -#endif - struct taskqueue *tq; - - /* - ** Queues: - ** This is the irq holder, it has - ** and RX/TX pair or rings associated - ** with it. - */ - struct ix_queue *queues; - - /* - * Transmit rings: - * Allocated at run time, an array of rings. - */ - struct tx_ring *tx_rings; - int num_tx_desc; - - /* - * Receive rings: - * Allocated at run time, an array of rings. - */ - struct rx_ring *rx_rings; - int num_rx_desc; - u64 que_mask; - u32 rx_process_limit; - - /* Multicast array memory */ - u8 *mta; - - int intr_rate; - - /* Misc stats maintained by the driver */ - unsigned long dropped_pkts; - unsigned long mbuf_defrag_failed; - unsigned long mbuf_header_failed; - unsigned long mbuf_packet_failed; - unsigned long no_tx_map_avail; - unsigned long no_tx_dma_setup; - unsigned long watchdog_events; - unsigned long tso_tx; - unsigned long link_irq; - - struct ixgbe_hw_stats stats; - - struct lwkt_serialize serializer; - struct sysctl_ctx_list sysctl_ctx; - struct sysctl_oid *sysctl_tree; -}; - -/* Precision Time Sync (IEEE 1588) defines */ -#define ETHERTYPE_IEEE1588 0x88F7 -#define PICOSECS_PER_TICK 20833 -#define TSYNC_UDP_PORT 319 /* UDP port for the protocol */ -#define IXGBE_ADVTXD_TSTAMP 0x00080000 - - -#define IXGBE_CORE_LOCK_INIT(_sc, _name) \ - lockinit(&(_sc)->core_lock, _name, 0, LK_CANRECURSE) -#define IXGBE_TX_LOCK_INIT(_sc) lwkt_serialize_init(&(_sc)->tx_serialize) -#define IXGBE_CORE_LOCK_DESTROY(_sc) lockuninit(&(_sc)->core_lock) -#define IXGBE_TX_LOCK_DESTROY(_sc) -#define IXGBE_RX_LOCK_DESTROY(_sc) lockuninit(&(_sc)->rx_lock) -#define IXGBE_CORE_LOCK(_sc) lockmgr(&(_sc)->core_lock, LK_EXCLUSIVE) -#define IXGBE_TX_LOCK(_sc) lwkt_serialize_enter(&(_sc)->tx_serialize) -#define IXGBE_TX_TRYLOCK(_sc) lwkt_serialize_try(&(_sc)->tx_serialize) -#define IXGBE_RX_LOCK(_sc) lockmgr(&(_sc)->rx_lock, LK_EXCLUSIVE) -#define IXGBE_CORE_UNLOCK(_sc) lockmgr(&(_sc)->core_lock, LK_RELEASE) -#define IXGBE_TX_UNLOCK(_sc) lwkt_serialize_exit(&(_sc)->tx_serialize) -#define IXGBE_RX_UNLOCK(_sc) lockmgr(&(_sc)->rx_lock, LK_RELEASE) -#define IXGBE_CORE_LOCK_ASSERT(_sc) KKASSERT(lockstatus(&(_sc)->core_lock, curthread) !=0) -#define IXGBE_TX_LOCK_ASSERT(_sc) ASSERT_SERIALIZED(&(_sc)->tx_serialize) - - -static inline bool -ixgbe_is_sfp(struct ixgbe_hw *hw) -{ - switch (hw->phy.type) { - case ixgbe_phy_sfp_avago: - case ixgbe_phy_sfp_ftl: - case ixgbe_phy_sfp_intel: - case ixgbe_phy_sfp_unknown: - case ixgbe_phy_sfp_passive_tyco: - case ixgbe_phy_sfp_passive_unknown: - return TRUE; - default: - return FALSE; - } -} - -/* -** Find the number of unrefreshed RX descriptors -*/ -static inline u16 -ixgbe_rx_unrefreshed(struct rx_ring *rxr) -{ - struct adapter *adapter = rxr->adapter; - - if (rxr->next_to_check > rxr->next_to_refresh) - return (rxr->next_to_check - rxr->next_to_refresh - 1); - else - return ((adapter->num_rx_desc + rxr->next_to_check) - - rxr->next_to_refresh - 1); -} - -#endif /* _IXGBE_H_ */ diff --git a/sys/dev/netif/ixgbe/ixgbe_defines.h b/sys/dev/netif/ixgbe/ixgbe_defines.h deleted file mode 100644 index 6cf3ae359e..0000000000 --- a/sys/dev/netif/ixgbe/ixgbe_defines.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2012 François Tigeot - * 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 DragonFly Project 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 HOLDERS 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. - */ - -#ifndef _IXGBE_DEFINES_H_ -#define _IXGBE_DEFINES_H_ - -#ifndef IFCAP_VLAN_HWFILTER -#define IFCAP_VLAN_HWFILTER 0x10000 /* interface hw can filter vlan tag */ -#endif - -#ifndef PI_NET -#define PI_NET TDPRI_KERN_DAEMON -#endif - -#endif /* _IXGBE_DEFINES_H */ -- 2.41.0