xref: /freebsd/sys/dev/ixl/if_ixl.c (revision 51e235148a4becba94e824a44bd69687644a7f56)
161ae650dSJack F Vogel /******************************************************************************
261ae650dSJack F Vogel 
3f4cc2d17SEric Joyner   Copyright (c) 2013-2018, Intel Corporation
461ae650dSJack F Vogel   All rights reserved.
561ae650dSJack F Vogel 
661ae650dSJack F Vogel   Redistribution and use in source and binary forms, with or without
761ae650dSJack F Vogel   modification, are permitted provided that the following conditions are met:
861ae650dSJack F Vogel 
961ae650dSJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
1061ae650dSJack F Vogel       this list of conditions and the following disclaimer.
1161ae650dSJack F Vogel 
1261ae650dSJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
1361ae650dSJack F Vogel       notice, this list of conditions and the following disclaimer in the
1461ae650dSJack F Vogel       documentation and/or other materials provided with the distribution.
1561ae650dSJack F Vogel 
1661ae650dSJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
1761ae650dSJack F Vogel       contributors may be used to endorse or promote products derived from
1861ae650dSJack F Vogel       this software without specific prior written permission.
1961ae650dSJack F Vogel 
2061ae650dSJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2161ae650dSJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2261ae650dSJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2361ae650dSJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2461ae650dSJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2561ae650dSJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2661ae650dSJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2761ae650dSJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2861ae650dSJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2961ae650dSJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3061ae650dSJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
3161ae650dSJack F Vogel 
3261ae650dSJack F Vogel ******************************************************************************/
3361ae650dSJack F Vogel 
3461ae650dSJack F Vogel #include "ixl.h"
3561ae650dSJack F Vogel #include "ixl_pf.h"
3661ae650dSJack F Vogel 
37cb6b8299SEric Joyner #ifdef IXL_IW
38cb6b8299SEric Joyner #include "ixl_iw.h"
39cb6b8299SEric Joyner #include "ixl_iw_int.h"
40cb6b8299SEric Joyner #endif
41cb6b8299SEric Joyner 
424294f337SSean Bruno #ifdef PCI_IOV
434294f337SSean Bruno #include "ixl_pf_iov.h"
44dcd7b3b2SJack F Vogel #endif
45dcd7b3b2SJack F Vogel 
4661ae650dSJack F Vogel /*********************************************************************
4761ae650dSJack F Vogel  *  Driver version
4861ae650dSJack F Vogel  *********************************************************************/
49f4cc2d17SEric Joyner #define IXL_DRIVER_VERSION_MAJOR	2
502984a8ddSEric Joyner #define IXL_DRIVER_VERSION_MINOR	3
511d02c6b1SKrzysztof Galazka #define IXL_DRIVER_VERSION_BUILD	3
52ceebc2f3SEric Joyner 
531031d839SEric Joyner #define IXL_DRIVER_VERSION_STRING			\
541031d839SEric Joyner     __XSTRING(IXL_DRIVER_VERSION_MAJOR) "."		\
551031d839SEric Joyner     __XSTRING(IXL_DRIVER_VERSION_MINOR) "."		\
56f4cc2d17SEric Joyner     __XSTRING(IXL_DRIVER_VERSION_BUILD) "-k"
5761ae650dSJack F Vogel 
5861ae650dSJack F Vogel /*********************************************************************
5961ae650dSJack F Vogel  *  PCI Device ID Table
6061ae650dSJack F Vogel  *
6161ae650dSJack F Vogel  *  Used by probe to select devices to load on
6261ae650dSJack F Vogel  *
631031d839SEric Joyner  *  ( Vendor ID, Device ID, Branding String )
6461ae650dSJack F Vogel  *********************************************************************/
6561ae650dSJack F Vogel 
66*51e23514SMarius Strobl static const pci_vendor_info_t ixl_vendor_info_array[] =
6761ae650dSJack F Vogel {
681031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, "Intel(R) Ethernet Controller X710 for 10GbE SFP+"),
691031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, "Intel(R) Ethernet Controller XL710 for 40GbE backplane"),
701031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, "Intel(R) Ethernet Controller X710 for 10GbE backplane"),
711031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, "Intel(R) Ethernet Controller XL710 for 40GbE QSFP+"),
721031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, "Intel(R) Ethernet Controller XL710 for 40GbE QSFP+"),
731031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, "Intel(R) Ethernet Controller X710 for 10GbE QSFP+"),
741031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, "Intel(R) Ethernet Controller X710 for 10GBASE-T"),
751031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, "Intel(R) Ethernet Controller X710/X557-AT 10GBASE-T"),
761031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, "Intel(R) Ethernet Connection X722 for 10GbE backplane"),
771031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, "Intel(R) Ethernet Connection X722 for 10GbE QSFP+"),
781031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, "Intel(R) Ethernet Connection X722 for 10GbE SFP+"),
791031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, "Intel(R) Ethernet Connection X722 for 1GbE"),
801031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, "Intel(R) Ethernet Connection X722 for 10GBASE-T"),
811031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, "Intel(R) Ethernet Connection X722 for 10GbE SFP+"),
821031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, "Intel(R) Ethernet Controller XXV710 for 25GbE backplane"),
831031d839SEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, "Intel(R) Ethernet Controller XXV710 for 25GbE SFP28"),
842984a8ddSEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_BC, "Intel(R) Ethernet Controller X710 for 10GBASE-T"),
852984a8ddSEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_SFP, "Intel(R) Ethernet Controller X710 for 10GbE SFP+"),
862984a8ddSEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_B, "Intel(R) Ethernet Controller X710 for 10GbE backplane"),
872984a8ddSEric Joyner 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_5G_BASE_T_BC, "Intel(R) Ethernet Controller V710 for 5GBASE-T"),
88b7b40e4aSKrzysztof Galazka 	PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_BC, "Intel(R) Ethernet Controller I710 for 1GBASE-T"),
8961ae650dSJack F Vogel 	/* required last entry */
901031d839SEric Joyner 	PVID_END
9161ae650dSJack F Vogel };
9261ae650dSJack F Vogel 
9361ae650dSJack F Vogel /*********************************************************************
9461ae650dSJack F Vogel  *  Function prototypes
9561ae650dSJack F Vogel  *********************************************************************/
961031d839SEric Joyner /*** IFLIB interface ***/
971031d839SEric Joyner static void	*ixl_register(device_t dev);
981031d839SEric Joyner static int	 ixl_if_attach_pre(if_ctx_t ctx);
991031d839SEric Joyner static int	 ixl_if_attach_post(if_ctx_t ctx);
1001031d839SEric Joyner static int	 ixl_if_detach(if_ctx_t ctx);
1011031d839SEric Joyner static int	 ixl_if_shutdown(if_ctx_t ctx);
1021031d839SEric Joyner static int	 ixl_if_suspend(if_ctx_t ctx);
1031031d839SEric Joyner static int	 ixl_if_resume(if_ctx_t ctx);
1041031d839SEric Joyner static int	 ixl_if_msix_intr_assign(if_ctx_t ctx, int msix);
1051031d839SEric Joyner static void	 ixl_if_enable_intr(if_ctx_t ctx);
1061031d839SEric Joyner static void	 ixl_if_disable_intr(if_ctx_t ctx);
1071031d839SEric Joyner static int	 ixl_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid);
1081031d839SEric Joyner static int	 ixl_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid);
1091031d839SEric Joyner static int	 ixl_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets);
1101031d839SEric Joyner static int	 ixl_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nqs, int nqsets);
1111031d839SEric Joyner static void	 ixl_if_queues_free(if_ctx_t ctx);
1121031d839SEric Joyner static void	 ixl_if_update_admin_status(if_ctx_t ctx);
1131031d839SEric Joyner static void	 ixl_if_multi_set(if_ctx_t ctx);
1141031d839SEric Joyner static int	 ixl_if_mtu_set(if_ctx_t ctx, uint32_t mtu);
1151031d839SEric Joyner static void	 ixl_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr);
1161031d839SEric Joyner static int	 ixl_if_media_change(if_ctx_t ctx);
1171031d839SEric Joyner static int	 ixl_if_promisc_set(if_ctx_t ctx, int flags);
1181031d839SEric Joyner static void	 ixl_if_timer(if_ctx_t ctx, uint16_t qid);
1191031d839SEric Joyner static void	 ixl_if_vlan_register(if_ctx_t ctx, u16 vtag);
1201031d839SEric Joyner static void	 ixl_if_vlan_unregister(if_ctx_t ctx, u16 vtag);
1211031d839SEric Joyner static uint64_t	 ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt);
1221031d839SEric Joyner static int	 ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req);
1231031d839SEric Joyner static int	 ixl_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data);
124cf150917SEric Joyner static bool	 ixl_if_needs_restart(if_ctx_t ctx, enum iflib_restart_event event);
12577c1fcecSEric Joyner #ifdef PCI_IOV
12677c1fcecSEric Joyner static void	 ixl_if_vflr_handle(if_ctx_t ctx);
12777c1fcecSEric Joyner #endif
1286c426059SEric Joyner 
1291031d839SEric Joyner /*** Other ***/
1301031d839SEric Joyner static void	 ixl_save_pf_tunables(struct ixl_pf *);
1311031d839SEric Joyner static int	 ixl_allocate_pci_resources(struct ixl_pf *);
132b4a7ce06SEric Joyner static void	 ixl_setup_ssctx(struct ixl_pf *pf);
133b4a7ce06SEric Joyner static void	 ixl_admin_timer(void *arg);
13461ae650dSJack F Vogel 
13561ae650dSJack F Vogel /*********************************************************************
13661ae650dSJack F Vogel  *  FreeBSD Device Interface Entry Points
13761ae650dSJack F Vogel  *********************************************************************/
13861ae650dSJack F Vogel 
13961ae650dSJack F Vogel static device_method_t ixl_methods[] = {
14061ae650dSJack F Vogel 	/* Device interface */
1411031d839SEric Joyner 	DEVMETHOD(device_register, ixl_register),
1421031d839SEric Joyner 	DEVMETHOD(device_probe, iflib_device_probe),
1431031d839SEric Joyner 	DEVMETHOD(device_attach, iflib_device_attach),
1441031d839SEric Joyner 	DEVMETHOD(device_detach, iflib_device_detach),
1451031d839SEric Joyner 	DEVMETHOD(device_shutdown, iflib_device_shutdown),
14656c2c47bSJack F Vogel #ifdef PCI_IOV
14777c1fcecSEric Joyner 	DEVMETHOD(pci_iov_init, iflib_device_iov_init),
14877c1fcecSEric Joyner 	DEVMETHOD(pci_iov_uninit, iflib_device_iov_uninit),
14977c1fcecSEric Joyner 	DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf),
15056c2c47bSJack F Vogel #endif
1511031d839SEric Joyner 	DEVMETHOD_END
15261ae650dSJack F Vogel };
15361ae650dSJack F Vogel 
15461ae650dSJack F Vogel static driver_t ixl_driver = {
15561ae650dSJack F Vogel 	"ixl", ixl_methods, sizeof(struct ixl_pf),
15661ae650dSJack F Vogel };
15761ae650dSJack F Vogel 
15883c0a9e8SJohn Baldwin DRIVER_MODULE(ixl, pci, ixl_driver, 0, 0);
1590dc34160SWarner Losh IFLIB_PNP_INFO(pci, ixl, ixl_vendor_info_array);
1601031d839SEric Joyner MODULE_VERSION(ixl, 3);
161cb6b8299SEric Joyner 
16261ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1);
16361ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1);
1641031d839SEric Joyner MODULE_DEPEND(ixl, iflib, 1, 1, 1);
1651031d839SEric Joyner 
1661031d839SEric Joyner static device_method_t ixl_if_methods[] = {
1671031d839SEric Joyner 	DEVMETHOD(ifdi_attach_pre, ixl_if_attach_pre),
1681031d839SEric Joyner 	DEVMETHOD(ifdi_attach_post, ixl_if_attach_post),
1691031d839SEric Joyner 	DEVMETHOD(ifdi_detach, ixl_if_detach),
1701031d839SEric Joyner 	DEVMETHOD(ifdi_shutdown, ixl_if_shutdown),
1711031d839SEric Joyner 	DEVMETHOD(ifdi_suspend, ixl_if_suspend),
1721031d839SEric Joyner 	DEVMETHOD(ifdi_resume, ixl_if_resume),
1731031d839SEric Joyner 	DEVMETHOD(ifdi_init, ixl_if_init),
1741031d839SEric Joyner 	DEVMETHOD(ifdi_stop, ixl_if_stop),
1751031d839SEric Joyner 	DEVMETHOD(ifdi_msix_intr_assign, ixl_if_msix_intr_assign),
1761031d839SEric Joyner 	DEVMETHOD(ifdi_intr_enable, ixl_if_enable_intr),
1771031d839SEric Joyner 	DEVMETHOD(ifdi_intr_disable, ixl_if_disable_intr),
1781031d839SEric Joyner 	DEVMETHOD(ifdi_rx_queue_intr_enable, ixl_if_rx_queue_intr_enable),
1791031d839SEric Joyner 	DEVMETHOD(ifdi_tx_queue_intr_enable, ixl_if_tx_queue_intr_enable),
1801031d839SEric Joyner 	DEVMETHOD(ifdi_tx_queues_alloc, ixl_if_tx_queues_alloc),
1811031d839SEric Joyner 	DEVMETHOD(ifdi_rx_queues_alloc, ixl_if_rx_queues_alloc),
1821031d839SEric Joyner 	DEVMETHOD(ifdi_queues_free, ixl_if_queues_free),
1831031d839SEric Joyner 	DEVMETHOD(ifdi_update_admin_status, ixl_if_update_admin_status),
1841031d839SEric Joyner 	DEVMETHOD(ifdi_multi_set, ixl_if_multi_set),
1851031d839SEric Joyner 	DEVMETHOD(ifdi_mtu_set, ixl_if_mtu_set),
1861031d839SEric Joyner 	DEVMETHOD(ifdi_media_status, ixl_if_media_status),
1871031d839SEric Joyner 	DEVMETHOD(ifdi_media_change, ixl_if_media_change),
1881031d839SEric Joyner 	DEVMETHOD(ifdi_promisc_set, ixl_if_promisc_set),
1891031d839SEric Joyner 	DEVMETHOD(ifdi_timer, ixl_if_timer),
1901031d839SEric Joyner 	DEVMETHOD(ifdi_vlan_register, ixl_if_vlan_register),
1911031d839SEric Joyner 	DEVMETHOD(ifdi_vlan_unregister, ixl_if_vlan_unregister),
1921031d839SEric Joyner 	DEVMETHOD(ifdi_get_counter, ixl_if_get_counter),
1931031d839SEric Joyner 	DEVMETHOD(ifdi_i2c_req, ixl_if_i2c_req),
1941031d839SEric Joyner 	DEVMETHOD(ifdi_priv_ioctl, ixl_if_priv_ioctl),
195cf150917SEric Joyner 	DEVMETHOD(ifdi_needs_restart, ixl_if_needs_restart),
19677c1fcecSEric Joyner #ifdef PCI_IOV
19777c1fcecSEric Joyner 	DEVMETHOD(ifdi_iov_init, ixl_if_iov_init),
19877c1fcecSEric Joyner 	DEVMETHOD(ifdi_iov_uninit, ixl_if_iov_uninit),
19977c1fcecSEric Joyner 	DEVMETHOD(ifdi_iov_vf_add, ixl_if_iov_vf_add),
20077c1fcecSEric Joyner 	DEVMETHOD(ifdi_vflr_handle, ixl_if_vflr_handle),
20177c1fcecSEric Joyner #endif
2021031d839SEric Joyner 	// ifdi_led_func
2031031d839SEric Joyner 	// ifdi_debug
2041031d839SEric Joyner 	DEVMETHOD_END
2051031d839SEric Joyner };
2061031d839SEric Joyner 
2071031d839SEric Joyner static driver_t ixl_if_driver = {
2081031d839SEric Joyner 	"ixl_if", ixl_if_methods, sizeof(struct ixl_pf)
2091031d839SEric Joyner };
21031830672SJack F Vogel 
21161ae650dSJack F Vogel /*
21261ae650dSJack F Vogel ** TUNEABLE PARAMETERS:
21361ae650dSJack F Vogel */
21461ae650dSJack F Vogel 
21520b91f0aSPawel Biernacki static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
21677c1fcecSEric Joyner     "ixl driver parameters");
21761ae650dSJack F Vogel 
218b4a7ce06SEric Joyner #ifdef IXL_DEBUG_FC
21961ae650dSJack F Vogel /*
220ceebc2f3SEric Joyner  * Leave this on unless you need to send flow control
221ceebc2f3SEric Joyner  * frames (or other control frames) from software
222ceebc2f3SEric Joyner  */
2234294f337SSean Bruno static int ixl_enable_tx_fc_filter = 1;
2244294f337SSean Bruno TUNABLE_INT("hw.ixl.enable_tx_fc_filter",
2254294f337SSean Bruno     &ixl_enable_tx_fc_filter);
2264294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN,
2274294f337SSean Bruno     &ixl_enable_tx_fc_filter, 0,
2284294f337SSean Bruno     "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources");
229b4a7ce06SEric Joyner #endif
230b4a7ce06SEric Joyner 
231b4a7ce06SEric Joyner #ifdef IXL_DEBUG
232b4a7ce06SEric Joyner static int ixl_debug_recovery_mode = 0;
233b4a7ce06SEric Joyner TUNABLE_INT("hw.ixl.debug_recovery_mode",
234b4a7ce06SEric Joyner     &ixl_debug_recovery_mode);
235b4a7ce06SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, debug_recovery_mode, CTLFLAG_RDTUN,
236b4a7ce06SEric Joyner     &ixl_debug_recovery_mode, 0,
237d7125850SGordon Bergling     "Act like when FW entered recovery mode (for debugging)");
238b4a7ce06SEric Joyner #endif
2394294f337SSean Bruno 
2401031d839SEric Joyner static int ixl_i2c_access_method = 0;
2411031d839SEric Joyner TUNABLE_INT("hw.ixl.i2c_access_method",
2421031d839SEric Joyner     &ixl_i2c_access_method);
2431031d839SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, i2c_access_method, CTLFLAG_RDTUN,
2441031d839SEric Joyner     &ixl_i2c_access_method, 0,
2451031d839SEric Joyner     IXL_SYSCTL_HELP_I2C_METHOD);
2461031d839SEric Joyner 
24777c1fcecSEric Joyner static int ixl_enable_vf_loopback = 1;
24877c1fcecSEric Joyner TUNABLE_INT("hw.ixl.enable_vf_loopback",
24977c1fcecSEric Joyner     &ixl_enable_vf_loopback);
25077c1fcecSEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, enable_vf_loopback, CTLFLAG_RDTUN,
25177c1fcecSEric Joyner     &ixl_enable_vf_loopback, 0,
25277c1fcecSEric Joyner     IXL_SYSCTL_HELP_VF_LOOPBACK);
25377c1fcecSEric Joyner 
254ceebc2f3SEric Joyner /*
255ceebc2f3SEric Joyner  * Different method for processing TX descriptor
256ceebc2f3SEric Joyner  * completion.
257ceebc2f3SEric Joyner  */
258ceebc2f3SEric Joyner static int ixl_enable_head_writeback = 1;
259ceebc2f3SEric Joyner TUNABLE_INT("hw.ixl.enable_head_writeback",
260ceebc2f3SEric Joyner     &ixl_enable_head_writeback);
261ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, enable_head_writeback, CTLFLAG_RDTUN,
262ceebc2f3SEric Joyner     &ixl_enable_head_writeback, 0,
263ceebc2f3SEric Joyner     "For detecting last completed TX descriptor by hardware, use value written by HW instead of checking descriptors");
264ceebc2f3SEric Joyner 
2654294f337SSean Bruno static int ixl_core_debug_mask = 0;
2664294f337SSean Bruno TUNABLE_INT("hw.ixl.core_debug_mask",
2674294f337SSean Bruno     &ixl_core_debug_mask);
2684294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, core_debug_mask, CTLFLAG_RDTUN,
2694294f337SSean Bruno     &ixl_core_debug_mask, 0,
2704294f337SSean Bruno     "Display debug statements that are printed in non-shared code");
2714294f337SSean Bruno 
2724294f337SSean Bruno static int ixl_shared_debug_mask = 0;
2734294f337SSean Bruno TUNABLE_INT("hw.ixl.shared_debug_mask",
2744294f337SSean Bruno     &ixl_shared_debug_mask);
2754294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, shared_debug_mask, CTLFLAG_RDTUN,
2764294f337SSean Bruno     &ixl_shared_debug_mask, 0,
2774294f337SSean Bruno     "Display debug statements that are printed in shared code");
2784294f337SSean Bruno 
2791031d839SEric Joyner #if 0
28061ae650dSJack F Vogel /*
28161ae650dSJack F Vogel ** Controls for Interrupt Throttling
28261ae650dSJack F Vogel **	- true/false for dynamic adjustment
28361ae650dSJack F Vogel ** 	- default values for static ITR
28461ae650dSJack F Vogel */
2851031d839SEric Joyner static int ixl_dynamic_rx_itr = 0;
28661ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr);
28761ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN,
28861ae650dSJack F Vogel     &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate");
28961ae650dSJack F Vogel 
2901031d839SEric Joyner static int ixl_dynamic_tx_itr = 0;
29161ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr);
29261ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN,
29361ae650dSJack F Vogel     &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate");
2941031d839SEric Joyner #endif
29561ae650dSJack F Vogel 
2964294f337SSean Bruno static int ixl_rx_itr = IXL_ITR_8K;
29761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr);
29861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN,
29961ae650dSJack F Vogel     &ixl_rx_itr, 0, "RX Interrupt Rate");
30061ae650dSJack F Vogel 
3014294f337SSean Bruno static int ixl_tx_itr = IXL_ITR_4K;
30261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr);
30361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN,
30461ae650dSJack F Vogel     &ixl_tx_itr, 0, "TX Interrupt Rate");
30561ae650dSJack F Vogel 
30620a52706SKrzysztof Galazka static int ixl_flow_control = -1;
30720a52706SKrzysztof Galazka SYSCTL_INT(_hw_ixl, OID_AUTO, flow_control, CTLFLAG_RDTUN,
30820a52706SKrzysztof Galazka     &ixl_flow_control, 0, "Initial Flow Control setting");
30920a52706SKrzysztof Galazka 
310cb6b8299SEric Joyner #ifdef IXL_IW
311cb6b8299SEric Joyner int ixl_enable_iwarp = 0;
312cb6b8299SEric Joyner TUNABLE_INT("hw.ixl.enable_iwarp", &ixl_enable_iwarp);
313ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, enable_iwarp, CTLFLAG_RDTUN,
314ceebc2f3SEric Joyner     &ixl_enable_iwarp, 0, "iWARP enabled");
315ceebc2f3SEric Joyner 
316ceebc2f3SEric Joyner int ixl_limit_iwarp_msix = IXL_IW_MAX_MSIX;
317ceebc2f3SEric Joyner TUNABLE_INT("hw.ixl.limit_iwarp_msix", &ixl_limit_iwarp_msix);
318ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, limit_iwarp_msix, CTLFLAG_RDTUN,
319b97de13aSMarius Strobl     &ixl_limit_iwarp_msix, 0, "Limit MSI-X vectors assigned to iWARP");
320cb6b8299SEric Joyner #endif
321cb6b8299SEric Joyner 
3221031d839SEric Joyner extern struct if_txrx ixl_txrx_hwb;
3231031d839SEric Joyner extern struct if_txrx ixl_txrx_dwb;
324e5100ee2SJack F Vogel 
3251031d839SEric Joyner static struct if_shared_ctx ixl_sctx_init = {
3261031d839SEric Joyner 	.isc_magic = IFLIB_MAGIC,
3271031d839SEric Joyner 	.isc_q_align = PAGE_SIZE,
3287f87c040SMarius Strobl 	.isc_tx_maxsize = IXL_TSO_SIZE + sizeof(struct ether_vlan_header),
3291031d839SEric Joyner 	.isc_tx_maxsegsize = IXL_MAX_DMA_SEG_SIZE,
3307f87c040SMarius Strobl 	.isc_tso_maxsize = IXL_TSO_SIZE + sizeof(struct ether_vlan_header),
3317f87c040SMarius Strobl 	.isc_tso_maxsegsize = IXL_MAX_DMA_SEG_SIZE,
3321031d839SEric Joyner 	.isc_rx_maxsize = 16384,
3331031d839SEric Joyner 	.isc_rx_nsegments = IXL_MAX_RX_SEGS,
3341031d839SEric Joyner 	.isc_rx_maxsegsize = IXL_MAX_DMA_SEG_SIZE,
3351031d839SEric Joyner 	.isc_nfl = 1,
3361031d839SEric Joyner 	.isc_ntxqs = 1,
3371031d839SEric Joyner 	.isc_nrxqs = 1,
3381031d839SEric Joyner 
3391031d839SEric Joyner 	.isc_admin_intrcnt = 1,
3401031d839SEric Joyner 	.isc_vendor_info = ixl_vendor_info_array,
3411031d839SEric Joyner 	.isc_driver_version = IXL_DRIVER_VERSION_STRING,
3421031d839SEric Joyner 	.isc_driver = &ixl_if_driver,
34337761e2eSEric Joyner 	.isc_flags = IFLIB_NEED_SCRATCH | IFLIB_NEED_ZERO_CSUM | IFLIB_TSO_INIT_IP | IFLIB_ADMIN_ALWAYS_RUN,
3441031d839SEric Joyner 
3451031d839SEric Joyner 	.isc_nrxd_min = {IXL_MIN_RING},
3461031d839SEric Joyner 	.isc_ntxd_min = {IXL_MIN_RING},
3471031d839SEric Joyner 	.isc_nrxd_max = {IXL_MAX_RING},
3481031d839SEric Joyner 	.isc_ntxd_max = {IXL_MAX_RING},
3491031d839SEric Joyner 	.isc_nrxd_default = {IXL_DEFAULT_RING},
3501031d839SEric Joyner 	.isc_ntxd_default = {IXL_DEFAULT_RING},
3511031d839SEric Joyner };
3521031d839SEric Joyner 
3531031d839SEric Joyner /*** Functions ***/
3541031d839SEric Joyner static void *
ixl_register(device_t dev)3551031d839SEric Joyner ixl_register(device_t dev)
3561031d839SEric Joyner {
357ffe3def9SMark Johnston 	return (&ixl_sctx_init);
3581031d839SEric Joyner }
35961ae650dSJack F Vogel 
36061ae650dSJack F Vogel static int
ixl_allocate_pci_resources(struct ixl_pf * pf)3611031d839SEric Joyner ixl_allocate_pci_resources(struct ixl_pf *pf)
36261ae650dSJack F Vogel {
3631031d839SEric Joyner 	device_t dev = iflib_get_dev(pf->vsi.ctx);
36477c1fcecSEric Joyner 	struct i40e_hw *hw = &pf->hw;
36577c1fcecSEric Joyner 	int             rid;
36661ae650dSJack F Vogel 
3671031d839SEric Joyner 	/* Map BAR0 */
3681031d839SEric Joyner 	rid = PCIR_BAR(0);
3691031d839SEric Joyner 	pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
3701031d839SEric Joyner 	    &rid, RF_ACTIVE);
37161ae650dSJack F Vogel 
3721031d839SEric Joyner 	if (!(pf->pci_mem)) {
3731031d839SEric Joyner 		device_printf(dev, "Unable to allocate bus resource: PCI memory\n");
37461ae650dSJack F Vogel 		return (ENXIO);
37561ae650dSJack F Vogel 	}
37661ae650dSJack F Vogel 
3771031d839SEric Joyner 	/* Save off the PCI information */
3781031d839SEric Joyner 	hw->vendor_id = pci_get_vendor(dev);
3791031d839SEric Joyner 	hw->device_id = pci_get_device(dev);
3801031d839SEric Joyner 	hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
3811031d839SEric Joyner 	hw->subsystem_vendor_id =
3821031d839SEric Joyner 	    pci_read_config(dev, PCIR_SUBVEND_0, 2);
3831031d839SEric Joyner 	hw->subsystem_device_id =
3841031d839SEric Joyner 	    pci_read_config(dev, PCIR_SUBDEV_0, 2);
3854294f337SSean Bruno 
3861031d839SEric Joyner 	hw->bus.device = pci_get_slot(dev);
3871031d839SEric Joyner 	hw->bus.func = pci_get_function(dev);
3884294f337SSean Bruno 
3891031d839SEric Joyner 	/* Save off register access information */
3901031d839SEric Joyner 	pf->osdep.mem_bus_space_tag =
3911031d839SEric Joyner 		rman_get_bustag(pf->pci_mem);
3921031d839SEric Joyner 	pf->osdep.mem_bus_space_handle =
3931031d839SEric Joyner 		rman_get_bushandle(pf->pci_mem);
3941031d839SEric Joyner 	pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem);
3951031d839SEric Joyner 	pf->osdep.flush_reg = I40E_GLGEN_STAT;
3961031d839SEric Joyner 	pf->osdep.dev = dev;
397cb6b8299SEric Joyner 
3981031d839SEric Joyner 	pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle;
3991031d839SEric Joyner 	pf->hw.back = &pf->osdep;
4004294f337SSean Bruno 
4014294f337SSean Bruno  	return (0);
4024294f337SSean Bruno }
4034294f337SSean Bruno 
404b4a7ce06SEric Joyner static void
ixl_setup_ssctx(struct ixl_pf * pf)405b4a7ce06SEric Joyner ixl_setup_ssctx(struct ixl_pf *pf)
406b4a7ce06SEric Joyner {
407b4a7ce06SEric Joyner 	if_softc_ctx_t scctx = pf->vsi.shared;
408b4a7ce06SEric Joyner 	struct i40e_hw *hw = &pf->hw;
409b4a7ce06SEric Joyner 
410b4a7ce06SEric Joyner 	if (IXL_PF_IN_RECOVERY_MODE(pf)) {
411b4a7ce06SEric Joyner 		scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 1;
412b4a7ce06SEric Joyner 		scctx->isc_ntxqsets = scctx->isc_nrxqsets = 1;
413b4a7ce06SEric Joyner 	} else if (hw->mac.type == I40E_MAC_X722)
414b4a7ce06SEric Joyner 		scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 128;
415b4a7ce06SEric Joyner 	else
416b4a7ce06SEric Joyner 		scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 64;
417b4a7ce06SEric Joyner 
418b4a7ce06SEric Joyner 	if (pf->vsi.enable_head_writeback) {
419b4a7ce06SEric Joyner 		scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0]
420b4a7ce06SEric Joyner 		    * sizeof(struct i40e_tx_desc) + sizeof(u32), DBA_ALIGN);
421b4a7ce06SEric Joyner 		scctx->isc_txrx = &ixl_txrx_hwb;
422b4a7ce06SEric Joyner 	} else {
423b4a7ce06SEric Joyner 		scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0]
424b4a7ce06SEric Joyner 		    * sizeof(struct i40e_tx_desc), DBA_ALIGN);
425b4a7ce06SEric Joyner 		scctx->isc_txrx = &ixl_txrx_dwb;
426b4a7ce06SEric Joyner 	}
427b4a7ce06SEric Joyner 
428b4a7ce06SEric Joyner 	scctx->isc_txrx->ift_legacy_intr = ixl_intr;
429b4a7ce06SEric Joyner 	scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0]
430b4a7ce06SEric Joyner 	    * sizeof(union i40e_32byte_rx_desc), DBA_ALIGN);
431b4a7ce06SEric Joyner 	scctx->isc_msix_bar = PCIR_BAR(IXL_MSIX_BAR);
432b4a7ce06SEric Joyner 	scctx->isc_tx_nsegments = IXL_MAX_TX_SEGS;
433b4a7ce06SEric Joyner 	scctx->isc_tx_tso_segments_max = IXL_MAX_TSO_SEGS;
434b4a7ce06SEric Joyner 	scctx->isc_tx_tso_size_max = IXL_TSO_SIZE;
435b4a7ce06SEric Joyner 	scctx->isc_tx_tso_segsize_max = IXL_MAX_DMA_SEG_SIZE;
436b4a7ce06SEric Joyner 	scctx->isc_rss_table_size = pf->hw.func_caps.rss_table_size;
437b4a7ce06SEric Joyner 	scctx->isc_tx_csum_flags = CSUM_OFFLOAD;
438b4a7ce06SEric Joyner 	scctx->isc_capabilities = scctx->isc_capenable = IXL_CAPS;
439b4a7ce06SEric Joyner }
440b4a7ce06SEric Joyner 
441b4a7ce06SEric Joyner static void
ixl_admin_timer(void * arg)442b4a7ce06SEric Joyner ixl_admin_timer(void *arg)
443b4a7ce06SEric Joyner {
444b4a7ce06SEric Joyner 	struct ixl_pf *pf = (struct ixl_pf *)arg;
445b4a7ce06SEric Joyner 
446ba2f531fSKrzysztof Galazka 	if (ixl_test_state(&pf->state, IXL_STATE_LINK_POLLING)) {
447ba2f531fSKrzysztof Galazka 		struct i40e_hw *hw = &pf->hw;
448ba2f531fSKrzysztof Galazka 		sbintime_t stime;
449ba2f531fSKrzysztof Galazka 		enum i40e_status_code status;
450ba2f531fSKrzysztof Galazka 
451ba2f531fSKrzysztof Galazka 		hw->phy.get_link_info = TRUE;
452ba2f531fSKrzysztof Galazka 		status = i40e_get_link_status(hw, &pf->link_up);
453ba2f531fSKrzysztof Galazka 		if (status == I40E_SUCCESS) {
454ba2f531fSKrzysztof Galazka 			ixl_clear_state(&pf->state, IXL_STATE_LINK_POLLING);
455ba2f531fSKrzysztof Galazka 			/* OS link info is updated in the admin task */
456ba2f531fSKrzysztof Galazka 		} else {
457ba2f531fSKrzysztof Galazka 			device_printf(pf->dev,
458ba2f531fSKrzysztof Galazka 			    "%s: i40e_get_link_status status %s, aq error %s\n",
459ba2f531fSKrzysztof Galazka 			    __func__, i40e_stat_str(hw, status),
460ba2f531fSKrzysztof Galazka 			    i40e_aq_str(hw, hw->aq.asq_last_status));
461ba2f531fSKrzysztof Galazka 			stime = getsbinuptime();
462ba2f531fSKrzysztof Galazka 			if (stime - pf->link_poll_start > IXL_PF_MAX_LINK_POLL) {
463ba2f531fSKrzysztof Galazka 				device_printf(pf->dev, "Polling link status failed\n");
464ba2f531fSKrzysztof Galazka 				ixl_clear_state(&pf->state, IXL_STATE_LINK_POLLING);
465ba2f531fSKrzysztof Galazka 			}
466ba2f531fSKrzysztof Galazka 		}
467ba2f531fSKrzysztof Galazka 	}
468ba2f531fSKrzysztof Galazka 
469b4a7ce06SEric Joyner 	/* Fire off the admin task */
470b4a7ce06SEric Joyner 	iflib_admin_intr_deferred(pf->vsi.ctx);
471b4a7ce06SEric Joyner 
472b4a7ce06SEric Joyner 	/* Reschedule the admin timer */
473b4a7ce06SEric Joyner 	callout_schedule(&pf->admin_timer, hz/2);
474b4a7ce06SEric Joyner }
475b4a7ce06SEric Joyner 
476b4a7ce06SEric Joyner static int
ixl_attach_pre_recovery_mode(struct ixl_pf * pf)477b4a7ce06SEric Joyner ixl_attach_pre_recovery_mode(struct ixl_pf *pf)
478b4a7ce06SEric Joyner {
479b4a7ce06SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
480b4a7ce06SEric Joyner 	struct i40e_hw *hw = &pf->hw;
481b4a7ce06SEric Joyner 	device_t dev = pf->dev;
482b4a7ce06SEric Joyner 
483b4a7ce06SEric Joyner 	device_printf(dev, "Firmware recovery mode detected. Limiting functionality. Refer to Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n");
484b4a7ce06SEric Joyner 
485b4a7ce06SEric Joyner 	i40e_get_mac_addr(hw, hw->mac.addr);
486b4a7ce06SEric Joyner 
487b4a7ce06SEric Joyner 	if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) {
488b4a7ce06SEric Joyner 		ixl_configure_intr0_msix(pf);
489b4a7ce06SEric Joyner 		ixl_enable_intr0(hw);
490b4a7ce06SEric Joyner 	}
491b4a7ce06SEric Joyner 
492b4a7ce06SEric Joyner 	ixl_setup_ssctx(pf);
493b4a7ce06SEric Joyner 
494b4a7ce06SEric Joyner 	return (0);
495b4a7ce06SEric Joyner }
496b4a7ce06SEric Joyner 
49761ae650dSJack F Vogel static int
ixl_if_attach_pre(if_ctx_t ctx)4981031d839SEric Joyner ixl_if_attach_pre(if_ctx_t ctx)
49961ae650dSJack F Vogel {
5001031d839SEric Joyner 	device_t dev;
50161ae650dSJack F Vogel 	struct ixl_pf *pf;
50261ae650dSJack F Vogel 	struct i40e_hw *hw;
50361ae650dSJack F Vogel 	struct ixl_vsi *vsi;
504b4a7ce06SEric Joyner 	enum i40e_get_fw_lldp_status_resp lldp_status;
5051031d839SEric Joyner 	struct i40e_filter_control_settings filter;
5064294f337SSean Bruno 	enum i40e_status_code status;
50761ae650dSJack F Vogel 	int error = 0;
50861ae650dSJack F Vogel 
5091031d839SEric Joyner 	dev = iflib_get_dev(ctx);
5101031d839SEric Joyner 	pf = iflib_get_softc(ctx);
51177c1fcecSEric Joyner 
512c65f571cSLeandro Lupori 	INIT_DBG_DEV(dev, "begin");
513c65f571cSLeandro Lupori 
5141031d839SEric Joyner 	vsi = &pf->vsi;
5151031d839SEric Joyner 	vsi->back = pf;
5161031d839SEric Joyner 	pf->dev = dev;
51761ae650dSJack F Vogel 	hw = &pf->hw;
51861ae650dSJack F Vogel 
51977c1fcecSEric Joyner 	vsi->dev = dev;
5201031d839SEric Joyner 	vsi->hw = &pf->hw;
5211031d839SEric Joyner 	vsi->id = 0;
5221031d839SEric Joyner 	vsi->num_vlans = 0;
5231031d839SEric Joyner 	vsi->ctx = ctx;
5241031d839SEric Joyner 	vsi->media = iflib_get_media(ctx);
525b4a7ce06SEric Joyner 	vsi->shared = iflib_get_softc_ctx(ctx);
526b4a7ce06SEric Joyner 
527b4a7ce06SEric Joyner 	snprintf(pf->admin_mtx_name, sizeof(pf->admin_mtx_name),
528b4a7ce06SEric Joyner 	    "%s:admin", device_get_nameunit(dev));
529b4a7ce06SEric Joyner 	mtx_init(&pf->admin_mtx, pf->admin_mtx_name, NULL, MTX_DEF);
530b4a7ce06SEric Joyner 	callout_init_mtx(&pf->admin_timer, &pf->admin_mtx, 0);
53161ae650dSJack F Vogel 
5324294f337SSean Bruno 	/* Save tunable values */
5331031d839SEric Joyner 	ixl_save_pf_tunables(pf);
53461ae650dSJack F Vogel 
53561ae650dSJack F Vogel 	/* Do PCI setup - map BAR0, etc */
53661ae650dSJack F Vogel 	if (ixl_allocate_pci_resources(pf)) {
53761ae650dSJack F Vogel 		device_printf(dev, "Allocation of PCI resources failed\n");
53861ae650dSJack F Vogel 		error = ENXIO;
5391031d839SEric Joyner 		goto err_pci_res;
54061ae650dSJack F Vogel 	}
54161ae650dSJack F Vogel 
54261ae650dSJack F Vogel 	/* Establish a clean starting point */
54361ae650dSJack F Vogel 	i40e_clear_hw(hw);
544b4a7ce06SEric Joyner 	i40e_set_mac_type(hw);
545b4a7ce06SEric Joyner 
546b4a7ce06SEric Joyner 	error = ixl_pf_reset(pf);
547b4a7ce06SEric Joyner 	if (error)
54861ae650dSJack F Vogel 		goto err_out;
54961ae650dSJack F Vogel 
55061ae650dSJack F Vogel 	/* Initialize the shared code */
5514294f337SSean Bruno 	status = i40e_init_shared_code(hw);
5524294f337SSean Bruno 	if (status) {
5534294f337SSean Bruno 		device_printf(dev, "Unable to initialize shared code, error %s\n",
5544294f337SSean Bruno 		    i40e_stat_str(hw, status));
55561ae650dSJack F Vogel 		error = EIO;
55661ae650dSJack F Vogel 		goto err_out;
55761ae650dSJack F Vogel 	}
55861ae650dSJack F Vogel 
55961ae650dSJack F Vogel 	/* Set up the admin queue */
5604294f337SSean Bruno 	hw->aq.num_arq_entries = IXL_AQ_LEN;
5614294f337SSean Bruno 	hw->aq.num_asq_entries = IXL_AQ_LEN;
5624294f337SSean Bruno 	hw->aq.arq_buf_size = IXL_AQ_BUF_SZ;
5634294f337SSean Bruno 	hw->aq.asq_buf_size = IXL_AQ_BUF_SZ;
5644294f337SSean Bruno 
5654294f337SSean Bruno 	status = i40e_init_adminq(hw);
5664294f337SSean Bruno 	if (status != 0 && status != I40E_ERR_FIRMWARE_API_VERSION) {
5674294f337SSean Bruno 		device_printf(dev, "Unable to initialize Admin Queue, error %s\n",
5684294f337SSean Bruno 		    i40e_stat_str(hw, status));
569fdb6f38aSEric Joyner 		error = EIO;
570fdb6f38aSEric Joyner 		goto err_out;
571fdb6f38aSEric Joyner 	}
5721d767a8eSEric Joyner 	ixl_print_nvm_version(pf);
5731d767a8eSEric Joyner 
5744294f337SSean Bruno 	if (status == I40E_ERR_FIRMWARE_API_VERSION) {
57561ae650dSJack F Vogel 		device_printf(dev, "The driver for the device stopped "
576ceebc2f3SEric Joyner 		    "because the NVM image is newer than expected.\n");
577ceebc2f3SEric Joyner 		device_printf(dev, "You must install the most recent version of "
57861ae650dSJack F Vogel 		    "the network driver.\n");
579fdb6f38aSEric Joyner 		error = EIO;
58061ae650dSJack F Vogel 		goto err_out;
58161ae650dSJack F Vogel 	}
58261ae650dSJack F Vogel 
58361ae650dSJack F Vogel         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
584ceebc2f3SEric Joyner 	    hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw)) {
58561ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
586ceebc2f3SEric Joyner 		    "a newer version of the NVM image than expected.\n");
587ceebc2f3SEric Joyner 		device_printf(dev, "Please install the most recent version "
588ceebc2f3SEric Joyner 		    "of the network driver.\n");
589ceebc2f3SEric Joyner 	} else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4) {
59061ae650dSJack F Vogel 		device_printf(dev, "The driver for the device detected "
591ceebc2f3SEric Joyner 		    "an older version of the NVM image than expected.\n");
592ceebc2f3SEric Joyner 		device_printf(dev, "Please update the NVM image.\n");
593ceebc2f3SEric Joyner 	}
59461ae650dSJack F Vogel 
595b4a7ce06SEric Joyner 	if (IXL_PF_IN_RECOVERY_MODE(pf)) {
596b4a7ce06SEric Joyner 		error = ixl_attach_pre_recovery_mode(pf);
597b4a7ce06SEric Joyner 		if (error)
598b4a7ce06SEric Joyner 			goto err_out;
599b4a7ce06SEric Joyner 		return (error);
600b4a7ce06SEric Joyner 	}
601b4a7ce06SEric Joyner 
60261ae650dSJack F Vogel 	/* Clear PXE mode */
60361ae650dSJack F Vogel 	i40e_clear_pxe_mode(hw);
60461ae650dSJack F Vogel 
60561ae650dSJack F Vogel 	/* Get capabilities from the device */
60661ae650dSJack F Vogel 	error = ixl_get_hw_capabilities(pf);
60761ae650dSJack F Vogel 	if (error) {
6081031d839SEric Joyner 		device_printf(dev, "get_hw_capabilities failed: %d\n",
6091031d839SEric Joyner 		    error);
61061ae650dSJack F Vogel 		goto err_get_cap;
61161ae650dSJack F Vogel 	}
61261ae650dSJack F Vogel 
61361ae650dSJack F Vogel 	/* Set up host memory cache */
614b4a7ce06SEric Joyner 	error = ixl_setup_hmc(pf);
615b4a7ce06SEric Joyner 	if (error)
61661ae650dSJack F Vogel 		goto err_mac_hmc;
61761ae650dSJack F Vogel 
618d4683565SEric Joyner 	/* Disable LLDP from the firmware for certain NVM versions */
619d4683565SEric Joyner 	if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
620ceebc2f3SEric Joyner 	    (pf->hw.aq.fw_maj_ver < 4)) {
621b4a7ce06SEric Joyner 		i40e_aq_stop_lldp(hw, true, false, NULL);
622b8f51b8cSPiotr Kubaj 		ixl_set_state(&pf->state, IXL_STATE_FW_LLDP_DISABLED);
623ceebc2f3SEric Joyner 	}
62461ae650dSJack F Vogel 
6252984a8ddSEric Joyner 	/* Try enabling Energy Efficient Ethernet (EEE) mode */
6262984a8ddSEric Joyner 	if (i40e_enable_eee(hw, true) == I40E_SUCCESS)
627b8f51b8cSPiotr Kubaj 		ixl_set_state(&pf->state, IXL_STATE_EEE_ENABLED);
6282984a8ddSEric Joyner 	else
629b8f51b8cSPiotr Kubaj 		ixl_clear_state(&pf->state, IXL_STATE_EEE_ENABLED);
6302984a8ddSEric Joyner 
6314294f337SSean Bruno 	/* Get MAC addresses from hardware */
63261ae650dSJack F Vogel 	i40e_get_mac_addr(hw, hw->mac.addr);
63361ae650dSJack F Vogel 	error = i40e_validate_mac_addr(hw->mac.addr);
63461ae650dSJack F Vogel 	if (error) {
63561ae650dSJack F Vogel 		device_printf(dev, "validate_mac_addr failed: %d\n", error);
63661ae650dSJack F Vogel 		goto err_mac_hmc;
63761ae650dSJack F Vogel 	}
63861ae650dSJack F Vogel 	bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
6391031d839SEric Joyner 	iflib_set_mac(ctx, hw->mac.addr);
64061ae650dSJack F Vogel 	i40e_get_port_mac_addr(hw, hw->mac.port_addr);
64161ae650dSJack F Vogel 
6421031d839SEric Joyner 	/* Set up the device filtering */
6431031d839SEric Joyner 	bzero(&filter, sizeof(filter));
6441031d839SEric Joyner 	filter.enable_ethtype = TRUE;
6451031d839SEric Joyner 	filter.enable_macvlan = TRUE;
6461031d839SEric Joyner 	filter.enable_fdir = FALSE;
6471031d839SEric Joyner 	filter.hash_lut_size = I40E_HASH_LUT_SIZE_512;
6481031d839SEric Joyner 	if (i40e_set_filter_control(hw, &filter))
6491031d839SEric Joyner 		device_printf(dev, "i40e_set_filter_control() failed\n");
6501031d839SEric Joyner 
651ceebc2f3SEric Joyner 	/* Query device FW LLDP status */
652b4a7ce06SEric Joyner 	if (i40e_get_fw_lldp_status(hw, &lldp_status) == I40E_SUCCESS) {
653b4a7ce06SEric Joyner 		if (lldp_status == I40E_GET_FW_LLDP_STATUS_DISABLED) {
654b8f51b8cSPiotr Kubaj 			ixl_set_state(&pf->state,
655b8f51b8cSPiotr Kubaj 			    IXL_STATE_FW_LLDP_DISABLED);
656b4a7ce06SEric Joyner 		} else {
657b8f51b8cSPiotr Kubaj 			ixl_clear_state(&pf->state,
658b8f51b8cSPiotr Kubaj 			    IXL_STATE_FW_LLDP_DISABLED);
659b4a7ce06SEric Joyner 		}
660b4a7ce06SEric Joyner 	}
661b4a7ce06SEric Joyner 
662ceebc2f3SEric Joyner 	/* Tell FW to apply DCB config on link up */
663ceebc2f3SEric Joyner 	i40e_aq_set_dcb_parameters(hw, true, NULL);
664ceebc2f3SEric Joyner 
6651031d839SEric Joyner 	/* Fill out iflib parameters */
666b4a7ce06SEric Joyner 	ixl_setup_ssctx(pf);
6674294f337SSean Bruno 
66877c1fcecSEric Joyner 	INIT_DBG_DEV(dev, "end");
6691031d839SEric Joyner 	return (0);
6701031d839SEric Joyner 
6711031d839SEric Joyner err_mac_hmc:
672b4a7ce06SEric Joyner 	ixl_shutdown_hmc(pf);
6731031d839SEric Joyner err_get_cap:
6741031d839SEric Joyner 	i40e_shutdown_adminq(hw);
6751031d839SEric Joyner err_out:
6761031d839SEric Joyner 	ixl_free_pci_resources(pf);
6771031d839SEric Joyner err_pci_res:
678b4a7ce06SEric Joyner 	mtx_lock(&pf->admin_mtx);
679b4a7ce06SEric Joyner 	callout_stop(&pf->admin_timer);
680b4a7ce06SEric Joyner 	mtx_unlock(&pf->admin_mtx);
681b4a7ce06SEric Joyner 	mtx_destroy(&pf->admin_mtx);
6821031d839SEric Joyner 	return (error);
68361ae650dSJack F Vogel }
68461ae650dSJack F Vogel 
6851031d839SEric Joyner static int
ixl_if_attach_post(if_ctx_t ctx)6861031d839SEric Joyner ixl_if_attach_post(if_ctx_t ctx)
6871031d839SEric Joyner {
6881031d839SEric Joyner 	device_t dev;
6891031d839SEric Joyner 	struct ixl_pf *pf;
6901031d839SEric Joyner 	struct i40e_hw *hw;
6911031d839SEric Joyner 	struct ixl_vsi *vsi;
6921031d839SEric Joyner 	int error = 0;
6931031d839SEric Joyner 	enum i40e_status_code status;
6941031d839SEric Joyner 
6951031d839SEric Joyner 	dev = iflib_get_dev(ctx);
6961031d839SEric Joyner 	pf = iflib_get_softc(ctx);
697c65f571cSLeandro Lupori 
698c65f571cSLeandro Lupori 	INIT_DBG_DEV(dev, "begin");
699c65f571cSLeandro Lupori 
7001031d839SEric Joyner 	vsi = &pf->vsi;
7011031d839SEric Joyner 	vsi->ifp = iflib_get_ifp(ctx);
7021031d839SEric Joyner 	hw = &pf->hw;
7031031d839SEric Joyner 
70477c1fcecSEric Joyner 	/* Save off determined number of queues for interface */
70577c1fcecSEric Joyner 	vsi->num_rx_queues = vsi->shared->isc_nrxqsets;
70677c1fcecSEric Joyner 	vsi->num_tx_queues = vsi->shared->isc_ntxqsets;
70777c1fcecSEric Joyner 
7084294f337SSean Bruno 	/* Setup OS network interface / ifnet */
7091031d839SEric Joyner 	if (ixl_setup_interface(dev, pf)) {
7104294f337SSean Bruno 		device_printf(dev, "interface setup failed!\n");
7114294f337SSean Bruno 		error = EIO;
7121031d839SEric Joyner 		goto err;
713223d846dSEric Joyner 	}
71461ae650dSJack F Vogel 
715b4a7ce06SEric Joyner 	if (IXL_PF_IN_RECOVERY_MODE(pf)) {
716b4a7ce06SEric Joyner 		/* Keep admin queue interrupts active while driver is loaded */
717b4a7ce06SEric Joyner 		if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) {
718b4a7ce06SEric Joyner 			ixl_configure_intr0_msix(pf);
719b4a7ce06SEric Joyner 			ixl_enable_intr0(hw);
720b4a7ce06SEric Joyner 		}
721b4a7ce06SEric Joyner 
722b4a7ce06SEric Joyner 		ixl_add_sysctls_recovery_mode(pf);
723b4a7ce06SEric Joyner 
724b4a7ce06SEric Joyner 		/* Start the admin timer */
725b4a7ce06SEric Joyner 		mtx_lock(&pf->admin_mtx);
726b4a7ce06SEric Joyner 		callout_reset(&pf->admin_timer, hz/2, ixl_admin_timer, pf);
727b4a7ce06SEric Joyner 		mtx_unlock(&pf->admin_mtx);
728b4a7ce06SEric Joyner 		return (0);
729b4a7ce06SEric Joyner 	}
730b4a7ce06SEric Joyner 
731b6c8f260SJack F Vogel 	error = ixl_switch_config(pf);
732b6c8f260SJack F Vogel 	if (error) {
7336c426059SEric Joyner 		device_printf(dev, "Initial ixl_switch_config() failed: %d\n",
7346c426059SEric Joyner 		     error);
7351031d839SEric Joyner 		goto err;
736b6c8f260SJack F Vogel 	}
737b6c8f260SJack F Vogel 
7381031d839SEric Joyner 	/* Add protocol filters to list */
7391031d839SEric Joyner 	ixl_init_filters(vsi);
7401031d839SEric Joyner 
7411031d839SEric Joyner 	/* Init queue allocation manager */
7421031d839SEric Joyner 	error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp);
7431031d839SEric Joyner 	if (error) {
7441031d839SEric Joyner 		device_printf(dev, "Failed to init queue manager for PF queues, error %d\n",
7451031d839SEric Joyner 		    error);
7461031d839SEric Joyner 		goto err;
7471031d839SEric Joyner 	}
7481031d839SEric Joyner 	/* reserve a contiguous allocation for the PF's VSI */
7491031d839SEric Joyner 	error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr,
7501031d839SEric Joyner 	    max(vsi->num_rx_queues, vsi->num_tx_queues), &pf->qtag);
7511031d839SEric Joyner 	if (error) {
7521031d839SEric Joyner 		device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n",
7531031d839SEric Joyner 		    error);
7541031d839SEric Joyner 		goto err;
7551031d839SEric Joyner 	}
7561031d839SEric Joyner 	device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n",
7571031d839SEric Joyner 	    pf->qtag.num_allocated, pf->qtag.num_active);
7581031d839SEric Joyner 
759ba2f531fSKrzysztof Galazka 	/* Determine link state */
760ba2f531fSKrzysztof Galazka 	error = ixl_attach_get_link_status(pf);
761ba2f531fSKrzysztof Galazka 	if (error == EINVAL)
762ba2f531fSKrzysztof Galazka 		goto err;
763ba2f531fSKrzysztof Galazka 
764223d846dSEric Joyner 	/* Limit PHY interrupts to link, autoneg, and modules failure */
7654294f337SSean Bruno 	status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK,
766223d846dSEric Joyner 	    NULL);
7674294f337SSean Bruno         if (status) {
7684294f337SSean Bruno 		device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s,"
7694294f337SSean Bruno 		    " aq_err %s\n", i40e_stat_str(hw, status),
7704294f337SSean Bruno 		    i40e_aq_str(hw, hw->aq.asq_last_status));
7711031d839SEric Joyner 		goto err;
772223d846dSEric Joyner 	}
773b6c8f260SJack F Vogel 
7741031d839SEric Joyner 	/* Get the bus configuration and set the shared code */
775cb6b8299SEric Joyner 	ixl_get_bus_info(pf);
77661ae650dSJack F Vogel 
7771031d839SEric Joyner 	/* Keep admin queue interrupts active while driver is loaded */
7781031d839SEric Joyner 	if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) {
7796c426059SEric Joyner  		ixl_configure_intr0_msix(pf);
780cb6b8299SEric Joyner  		ixl_enable_intr0(hw);
781cb6b8299SEric Joyner 	}
782cb6b8299SEric Joyner 
783cb6b8299SEric Joyner 	/* Set initial advertised speed sysctl value */
784ceebc2f3SEric Joyner 	ixl_set_initial_advertised_speeds(pf);
785cb6b8299SEric Joyner 
786fdb6f38aSEric Joyner 	/* Initialize statistics & add sysctls */
787fdb6f38aSEric Joyner 	ixl_add_device_sysctls(pf);
78861ae650dSJack F Vogel 	ixl_pf_reset_stats(pf);
78961ae650dSJack F Vogel 	ixl_update_stats_counters(pf);
79061ae650dSJack F Vogel 	ixl_add_hw_stats(pf);
79161ae650dSJack F Vogel 
79221802a12SKrzysztof Galazka 	/*
79321802a12SKrzysztof Galazka 	 * Driver may have been reloaded. Ensure that the link state
79421802a12SKrzysztof Galazka 	 * is consistent with current settings.
79521802a12SKrzysztof Galazka 	 */
796b8f51b8cSPiotr Kubaj 	ixl_set_link(pf, ixl_test_state(&pf->state, IXL_STATE_LINK_ACTIVE_ON_DOWN));
79721802a12SKrzysztof Galazka 
7981031d839SEric Joyner 	hw->phy.get_link_info = true;
799ba2f531fSKrzysztof Galazka 	status = i40e_get_link_status(hw, &pf->link_up);
800ba2f531fSKrzysztof Galazka 	if (status != I40E_SUCCESS) {
801ba2f531fSKrzysztof Galazka 		device_printf(dev,
802ba2f531fSKrzysztof Galazka 		    "%s get link status, status: %s aq_err=%s\n",
803ba2f531fSKrzysztof Galazka 		    __func__, i40e_stat_str(hw, status),
804ba2f531fSKrzysztof Galazka 		    i40e_aq_str(hw, hw->aq.asq_last_status));
805ba2f531fSKrzysztof Galazka 		/*
806ba2f531fSKrzysztof Galazka 		 * Most probably FW has not finished configuring PHY.
807ba2f531fSKrzysztof Galazka 		 * Retry periodically in a timer callback.
808ba2f531fSKrzysztof Galazka 		 */
809ba2f531fSKrzysztof Galazka 		ixl_set_state(&pf->state, IXL_STATE_LINK_POLLING);
810ba2f531fSKrzysztof Galazka 		pf->link_poll_start = getsbinuptime();
811ba2f531fSKrzysztof Galazka 	} else
8121031d839SEric Joyner 		ixl_update_link_status(pf);
81361ae650dSJack F Vogel 
81456c2c47bSJack F Vogel #ifdef PCI_IOV
8154294f337SSean Bruno 	ixl_initialize_sriov(pf);
81656c2c47bSJack F Vogel #endif
81756c2c47bSJack F Vogel 
818cb6b8299SEric Joyner #ifdef IXL_IW
819cb6b8299SEric Joyner 	if (hw->func_caps.iwarp && ixl_enable_iwarp) {
820cb6b8299SEric Joyner 		pf->iw_enabled = (pf->iw_msix > 0) ? true : false;
821cb6b8299SEric Joyner 		if (pf->iw_enabled) {
822cb6b8299SEric Joyner 			error = ixl_iw_pf_attach(pf);
823cb6b8299SEric Joyner 			if (error) {
824cb6b8299SEric Joyner 				device_printf(dev,
825b97de13aSMarius Strobl 				    "interfacing to iWARP driver failed: %d\n",
826cb6b8299SEric Joyner 				    error);
8271031d839SEric Joyner 				goto err;
828ceebc2f3SEric Joyner 			} else
829ceebc2f3SEric Joyner 				device_printf(dev, "iWARP ready\n");
830cb6b8299SEric Joyner 		} else
831b97de13aSMarius Strobl 			device_printf(dev, "iWARP disabled on this device "
832b97de13aSMarius Strobl 			    "(no MSI-X vectors)\n");
833cb6b8299SEric Joyner 	} else {
834cb6b8299SEric Joyner 		pf->iw_enabled = false;
835cb6b8299SEric Joyner 		device_printf(dev, "The device is not iWARP enabled\n");
836cb6b8299SEric Joyner 	}
837cb6b8299SEric Joyner #endif
838b4a7ce06SEric Joyner 	/* Start the admin timer */
839b4a7ce06SEric Joyner 	mtx_lock(&pf->admin_mtx);
840b4a7ce06SEric Joyner 	callout_reset(&pf->admin_timer, hz/2, ixl_admin_timer, pf);
841b4a7ce06SEric Joyner 	mtx_unlock(&pf->admin_mtx);
842cb6b8299SEric Joyner 
8431031d839SEric Joyner 	INIT_DBG_DEV(dev, "end");
84461ae650dSJack F Vogel 	return (0);
84561ae650dSJack F Vogel 
8461031d839SEric Joyner err:
8471031d839SEric Joyner 	INIT_DEBUGOUT("end: error %d", error);
8481031d839SEric Joyner 	/* ixl_if_detach() is called on error from this */
84961ae650dSJack F Vogel 	return (error);
85061ae650dSJack F Vogel }
85161ae650dSJack F Vogel 
85277c1fcecSEric Joyner /**
85377c1fcecSEric Joyner  * XXX: iflib always ignores the return value of detach()
85477c1fcecSEric Joyner  * -> This means that this isn't allowed to fail
85577c1fcecSEric Joyner  */
85661ae650dSJack F Vogel static int
ixl_if_detach(if_ctx_t ctx)8571031d839SEric Joyner ixl_if_detach(if_ctx_t ctx)
85861ae650dSJack F Vogel {
8591031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
86061ae650dSJack F Vogel 	struct ixl_vsi *vsi = &pf->vsi;
8611031d839SEric Joyner 	struct i40e_hw *hw = &pf->hw;
8621031d839SEric Joyner 	device_t dev = pf->dev;
8636c426059SEric Joyner 	enum i40e_status_code	status;
86477c1fcecSEric Joyner #ifdef IXL_IW
86556c2c47bSJack F Vogel 	int			error;
86656c2c47bSJack F Vogel #endif
86761ae650dSJack F Vogel 
8681031d839SEric Joyner 	INIT_DBG_DEV(dev, "begin");
869cb6b8299SEric Joyner 
870b4a7ce06SEric Joyner 	/* Stop the admin timer */
871b4a7ce06SEric Joyner 	mtx_lock(&pf->admin_mtx);
872b4a7ce06SEric Joyner 	callout_stop(&pf->admin_timer);
873b4a7ce06SEric Joyner 	mtx_unlock(&pf->admin_mtx);
874b4a7ce06SEric Joyner 	mtx_destroy(&pf->admin_mtx);
875b4a7ce06SEric Joyner 
876cb6b8299SEric Joyner #ifdef IXL_IW
877cb6b8299SEric Joyner 	if (ixl_enable_iwarp && pf->iw_enabled) {
878cb6b8299SEric Joyner 		error = ixl_iw_pf_detach(pf);
879cb6b8299SEric Joyner 		if (error == EBUSY) {
880cb6b8299SEric Joyner 			device_printf(dev, "iwarp in use; stop it first.\n");
88177c1fcecSEric Joyner 			//return (error);
882cb6b8299SEric Joyner 		}
883cb6b8299SEric Joyner 	}
884cb6b8299SEric Joyner #endif
8851031d839SEric Joyner 	/* Remove all previously allocated media types */
8861031d839SEric Joyner 	ifmedia_removeall(vsi->media);
887cb6b8299SEric Joyner 
8881031d839SEric Joyner 	/* Shutdown LAN HMC */
889b4a7ce06SEric Joyner 	ixl_shutdown_hmc(pf);
8901031d839SEric Joyner 
8911031d839SEric Joyner 	/* Shutdown admin queue */
8921031d839SEric Joyner 	ixl_disable_intr0(hw);
8931031d839SEric Joyner 	status = i40e_shutdown_adminq(hw);
8941031d839SEric Joyner 	if (status)
8951031d839SEric Joyner 		device_printf(dev,
8961031d839SEric Joyner 		    "i40e_shutdown_adminq() failed with status %s\n",
8971031d839SEric Joyner 		    i40e_stat_str(hw, status));
8981031d839SEric Joyner 
8994294f337SSean Bruno 	ixl_pf_qmgr_destroy(&pf->qmgr);
90061ae650dSJack F Vogel 	ixl_free_pci_resources(pf);
9017d4dceecSKrzysztof Galazka 	ixl_free_filters(&vsi->ftl);
9021031d839SEric Joyner 	INIT_DBG_DEV(dev, "end");
90361ae650dSJack F Vogel 	return (0);
90461ae650dSJack F Vogel }
90561ae650dSJack F Vogel 
9061031d839SEric Joyner static int
ixl_if_shutdown(if_ctx_t ctx)9071031d839SEric Joyner ixl_if_shutdown(if_ctx_t ctx)
9081031d839SEric Joyner {
9091031d839SEric Joyner 	int error = 0;
9101031d839SEric Joyner 
9111031d839SEric Joyner 	INIT_DEBUGOUT("ixl_if_shutdown: begin");
9121031d839SEric Joyner 
9131031d839SEric Joyner 	/* TODO: Call ixl_if_stop()? */
9141031d839SEric Joyner 
9151031d839SEric Joyner 	/* TODO: Then setup low power mode */
9161031d839SEric Joyner 
9171031d839SEric Joyner 	return (error);
9181031d839SEric Joyner }
91961ae650dSJack F Vogel 
92061ae650dSJack F Vogel static int
ixl_if_suspend(if_ctx_t ctx)9211031d839SEric Joyner ixl_if_suspend(if_ctx_t ctx)
92261ae650dSJack F Vogel {
9231031d839SEric Joyner 	int error = 0;
9241031d839SEric Joyner 
9251031d839SEric Joyner 	INIT_DEBUGOUT("ixl_if_suspend: begin");
9261031d839SEric Joyner 
9271031d839SEric Joyner 	/* TODO: Call ixl_if_stop()? */
9281031d839SEric Joyner 
9291031d839SEric Joyner 	/* TODO: Then setup low power mode */
9301031d839SEric Joyner 
9311031d839SEric Joyner 	return (error);
9321031d839SEric Joyner }
9331031d839SEric Joyner 
9341031d839SEric Joyner static int
ixl_if_resume(if_ctx_t ctx)9351031d839SEric Joyner ixl_if_resume(if_ctx_t ctx)
9361031d839SEric Joyner {
937402810d3SJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
9381031d839SEric Joyner 
9391031d839SEric Joyner 	INIT_DEBUGOUT("ixl_if_resume: begin");
9401031d839SEric Joyner 
9411031d839SEric Joyner 	/* Read & clear wake-up registers */
9421031d839SEric Joyner 
9431031d839SEric Joyner 	/* Required after D3->D0 transition */
944402810d3SJustin Hibbits 	if (if_getflags(ifp) & IFF_UP)
9451031d839SEric Joyner 		ixl_if_init(ctx);
9461031d839SEric Joyner 
94761ae650dSJack F Vogel 	return (0);
94861ae650dSJack F Vogel }
94961ae650dSJack F Vogel 
9501031d839SEric Joyner void
ixl_if_init(if_ctx_t ctx)9511031d839SEric Joyner ixl_if_init(if_ctx_t ctx)
9521031d839SEric Joyner {
9531031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
9541031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
9551031d839SEric Joyner 	struct i40e_hw	*hw = &pf->hw;
956402810d3SJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
9571031d839SEric Joyner 	device_t 	dev = iflib_get_dev(ctx);
9581031d839SEric Joyner 	u8		tmpaddr[ETHER_ADDR_LEN];
9591031d839SEric Joyner 	int		ret;
9601031d839SEric Joyner 
961b4a7ce06SEric Joyner 	if (IXL_PF_IN_RECOVERY_MODE(pf))
962b4a7ce06SEric Joyner 		return;
9631031d839SEric Joyner 	/*
9641031d839SEric Joyner 	 * If the aq is dead here, it probably means something outside of the driver
9651031d839SEric Joyner 	 * did something to the adapter, like a PF reset.
96677c1fcecSEric Joyner 	 * So, rebuild the driver's state here if that occurs.
9671031d839SEric Joyner 	 */
9681031d839SEric Joyner 	if (!i40e_check_asq_alive(&pf->hw)) {
9691031d839SEric Joyner 		device_printf(dev, "Admin Queue is down; resetting...\n");
9701031d839SEric Joyner 		ixl_teardown_hw_structs(pf);
971b4a7ce06SEric Joyner 		ixl_rebuild_hw_structs_after_reset(pf, false);
9721031d839SEric Joyner 	}
9731031d839SEric Joyner 
9741031d839SEric Joyner 	/* Get the latest mac address... User might use a LAA */
975402810d3SJustin Hibbits 	bcopy(if_getlladdr(vsi->ifp), tmpaddr, ETH_ALEN);
9767d4dceecSKrzysztof Galazka 	if (!ixl_ether_is_equal(hw->mac.addr, tmpaddr) &&
9771031d839SEric Joyner 	    (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) {
9787d4dceecSKrzysztof Galazka 		ixl_del_all_vlan_filters(vsi, hw->mac.addr);
9791031d839SEric Joyner 		bcopy(tmpaddr, hw->mac.addr, ETH_ALEN);
9801031d839SEric Joyner 		ret = i40e_aq_mac_address_write(hw,
9811031d839SEric Joyner 		    I40E_AQC_WRITE_TYPE_LAA_ONLY,
9821031d839SEric Joyner 		    hw->mac.addr, NULL);
9831031d839SEric Joyner 		if (ret) {
9841031d839SEric Joyner 			device_printf(dev, "LLA address change failed!!\n");
9851031d839SEric Joyner 			return;
9861031d839SEric Joyner 		}
9877d4dceecSKrzysztof Galazka 		/*
9887d4dceecSKrzysztof Galazka 		 * New filters are configured by ixl_reconfigure_filters
9897d4dceecSKrzysztof Galazka 		 * at the end of ixl_init_locked.
9907d4dceecSKrzysztof Galazka 		 */
9911031d839SEric Joyner 	}
9921031d839SEric Joyner 
9931031d839SEric Joyner 	iflib_set_mac(ctx, hw->mac.addr);
9941031d839SEric Joyner 
9951031d839SEric Joyner 	/* Prepare the VSI: rings, hmc contexts, etc... */
9961031d839SEric Joyner 	if (ixl_initialize_vsi(vsi)) {
9971031d839SEric Joyner 		device_printf(dev, "initialize vsi failed!!\n");
9981031d839SEric Joyner 		return;
9991031d839SEric Joyner 	}
10001031d839SEric Joyner 
100121802a12SKrzysztof Galazka 	ixl_set_link(pf, true);
100221802a12SKrzysztof Galazka 
100377c1fcecSEric Joyner 	/* Reconfigure multicast filters in HW */
10041031d839SEric Joyner 	ixl_if_multi_set(ctx);
10051031d839SEric Joyner 
10061031d839SEric Joyner 	/* Set up RSS */
10071031d839SEric Joyner 	ixl_config_rss(pf);
10081031d839SEric Joyner 
1009b97de13aSMarius Strobl 	/* Set up MSI-X routing and the ITR settings */
10101031d839SEric Joyner 	if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) {
10111031d839SEric Joyner 		ixl_configure_queue_intr_msix(pf);
10121031d839SEric Joyner 		ixl_configure_itr(pf);
10131031d839SEric Joyner 	} else
10141031d839SEric Joyner 		ixl_configure_legacy(pf);
10151031d839SEric Joyner 
10161031d839SEric Joyner 	if (vsi->enable_head_writeback)
10171031d839SEric Joyner 		ixl_init_tx_cidx(vsi);
10181031d839SEric Joyner 	else
10191031d839SEric Joyner 		ixl_init_tx_rsqs(vsi);
10201031d839SEric Joyner 
10211031d839SEric Joyner 	ixl_enable_rings(vsi);
10221031d839SEric Joyner 
10231031d839SEric Joyner 	i40e_aq_set_default_vsi(hw, vsi->seid, NULL);
10241031d839SEric Joyner 
102577c1fcecSEric Joyner 	/* Re-add configure filters to HW */
10261031d839SEric Joyner 	ixl_reconfigure_filters(vsi);
10271031d839SEric Joyner 
102877c1fcecSEric Joyner 	/* Configure promiscuous mode */
102977c1fcecSEric Joyner 	ixl_if_promisc_set(ctx, if_getflags(ifp));
103077c1fcecSEric Joyner 
10311031d839SEric Joyner #ifdef IXL_IW
10321031d839SEric Joyner 	if (ixl_enable_iwarp && pf->iw_enabled) {
10331031d839SEric Joyner 		ret = ixl_iw_pf_init(pf);
10341031d839SEric Joyner 		if (ret)
10351031d839SEric Joyner 			device_printf(dev,
10361031d839SEric Joyner 			    "initialize iwarp failed, code %d\n", ret);
10371031d839SEric Joyner 	}
10381031d839SEric Joyner #endif
10391031d839SEric Joyner }
10401031d839SEric Joyner 
10411031d839SEric Joyner void
ixl_if_stop(if_ctx_t ctx)10421031d839SEric Joyner ixl_if_stop(if_ctx_t ctx)
10431031d839SEric Joyner {
10441031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
1045402810d3SJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
10461031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
10471031d839SEric Joyner 
10481031d839SEric Joyner 	INIT_DEBUGOUT("ixl_if_stop: begin\n");
10491031d839SEric Joyner 
1050b4a7ce06SEric Joyner 	if (IXL_PF_IN_RECOVERY_MODE(pf))
1051b4a7ce06SEric Joyner 		return;
1052b4a7ce06SEric Joyner 
10531031d839SEric Joyner 	// TODO: This may need to be reworked
10541031d839SEric Joyner #ifdef IXL_IW
10551031d839SEric Joyner 	/* Stop iWARP device */
10561031d839SEric Joyner 	if (ixl_enable_iwarp && pf->iw_enabled)
10571031d839SEric Joyner 		ixl_iw_pf_stop(pf);
10581031d839SEric Joyner #endif
10591031d839SEric Joyner 
10601031d839SEric Joyner 	ixl_disable_rings_intr(vsi);
106177c1fcecSEric Joyner 	ixl_disable_rings(pf, vsi, &pf->qtag);
106221802a12SKrzysztof Galazka 
106321802a12SKrzysztof Galazka 	/*
106421802a12SKrzysztof Galazka 	 * Don't set link state if only reconfiguring
106521802a12SKrzysztof Galazka 	 * e.g. on MTU change.
106621802a12SKrzysztof Galazka 	 */
106721802a12SKrzysztof Galazka 	if ((if_getflags(ifp) & IFF_UP) == 0 &&
1068b8f51b8cSPiotr Kubaj 	    !ixl_test_state(&pf->state, IXL_STATE_LINK_ACTIVE_ON_DOWN))
106921802a12SKrzysztof Galazka 		ixl_set_link(pf, false);
10701031d839SEric Joyner }
10711031d839SEric Joyner 
10721031d839SEric Joyner static int
ixl_if_msix_intr_assign(if_ctx_t ctx,int msix)10731031d839SEric Joyner ixl_if_msix_intr_assign(if_ctx_t ctx, int msix)
10741031d839SEric Joyner {
10751031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
10761031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
10771031d839SEric Joyner 	struct ixl_rx_queue *rx_que = vsi->rx_queues;
10781031d839SEric Joyner 	struct ixl_tx_queue *tx_que = vsi->tx_queues;
10791031d839SEric Joyner 	int err, i, rid, vector = 0;
10801031d839SEric Joyner 	char buf[16];
10811031d839SEric Joyner 
108277c1fcecSEric Joyner 	MPASS(vsi->shared->isc_nrxqsets > 0);
108377c1fcecSEric Joyner 	MPASS(vsi->shared->isc_ntxqsets > 0);
108477c1fcecSEric Joyner 
10851031d839SEric Joyner 	/* Admin Que must use vector 0*/
10861031d839SEric Joyner 	rid = vector + 1;
10871031d839SEric Joyner 	err = iflib_irq_alloc_generic(ctx, &vsi->irq, rid, IFLIB_INTR_ADMIN,
10881031d839SEric Joyner 	    ixl_msix_adminq, pf, 0, "aq");
10891031d839SEric Joyner 	if (err) {
10901031d839SEric Joyner 		iflib_irq_free(ctx, &vsi->irq);
10911031d839SEric Joyner 		device_printf(iflib_get_dev(ctx),
109277c1fcecSEric Joyner 		    "Failed to register Admin Que handler");
10931031d839SEric Joyner 		return (err);
10941031d839SEric Joyner 	}
109517859d53SAndrew Gallatin 
109617859d53SAndrew Gallatin #ifdef PCI_IOV
109777c1fcecSEric Joyner 	/* Create soft IRQ for handling VFLRs */
1098af06fa26SEric Joyner 	iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_IOV, pf, 0, "iov");
109917859d53SAndrew Gallatin #endif
11001031d839SEric Joyner 
11011031d839SEric Joyner 	/* Now set up the stations */
110277c1fcecSEric Joyner 	for (i = 0, vector = 1; i < vsi->shared->isc_nrxqsets; i++, vector++, rx_que++) {
11031031d839SEric Joyner 		rid = vector + 1;
11041031d839SEric Joyner 
11051031d839SEric Joyner 		snprintf(buf, sizeof(buf), "rxq%d", i);
11061031d839SEric Joyner 		err = iflib_irq_alloc_generic(ctx, &rx_que->que_irq, rid,
110781be6552SMatt Macy 		    IFLIB_INTR_RXTX, ixl_msix_que, rx_que, rx_que->rxr.me, buf);
11081031d839SEric Joyner 		/* XXX: Does the driver work as expected if there are fewer num_rx_queues than
11091031d839SEric Joyner 		 * what's expected in the iflib context? */
11101031d839SEric Joyner 		if (err) {
11111031d839SEric Joyner 			device_printf(iflib_get_dev(ctx),
111277c1fcecSEric Joyner 			    "Failed to allocate queue RX int vector %d, err: %d\n", i, err);
11131031d839SEric Joyner 			vsi->num_rx_queues = i + 1;
11141031d839SEric Joyner 			goto fail;
11151031d839SEric Joyner 		}
11161031d839SEric Joyner 		rx_que->msix = vector;
11171031d839SEric Joyner 	}
11181031d839SEric Joyner 
11191031d839SEric Joyner 	bzero(buf, sizeof(buf));
11201031d839SEric Joyner 
112177c1fcecSEric Joyner 	for (i = 0; i < vsi->shared->isc_ntxqsets; i++, tx_que++) {
11221031d839SEric Joyner 		snprintf(buf, sizeof(buf), "txq%d", i);
11231031d839SEric Joyner 		iflib_softirq_alloc_generic(ctx,
112477c1fcecSEric Joyner 		    &vsi->rx_queues[i % vsi->shared->isc_nrxqsets].que_irq,
11251031d839SEric Joyner 		    IFLIB_INTR_TX, tx_que, tx_que->txr.me, buf);
11261031d839SEric Joyner 
11271031d839SEric Joyner 		/* TODO: Maybe call a strategy function for this to figure out which
11281031d839SEric Joyner 		* interrupts to map Tx queues to. I don't know if there's an immediately
11291031d839SEric Joyner 		* better way than this other than a user-supplied map, though. */
113077c1fcecSEric Joyner 		tx_que->msix = (i % vsi->shared->isc_nrxqsets) + 1;
11311031d839SEric Joyner 	}
11321031d839SEric Joyner 
11331031d839SEric Joyner 	return (0);
11341031d839SEric Joyner fail:
11351031d839SEric Joyner 	iflib_irq_free(ctx, &vsi->irq);
11361031d839SEric Joyner 	rx_que = vsi->rx_queues;
11371031d839SEric Joyner 	for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++)
11381031d839SEric Joyner 		iflib_irq_free(ctx, &rx_que->que_irq);
11391031d839SEric Joyner 	return (err);
11401031d839SEric Joyner }
11411031d839SEric Joyner 
11421031d839SEric Joyner /*
11431031d839SEric Joyner  * Enable all interrupts
11441031d839SEric Joyner  *
11451031d839SEric Joyner  * Called in:
11461031d839SEric Joyner  * iflib_init_locked, after ixl_if_init()
11471031d839SEric Joyner  */
11481031d839SEric Joyner static void
ixl_if_enable_intr(if_ctx_t ctx)11491031d839SEric Joyner ixl_if_enable_intr(if_ctx_t ctx)
11501031d839SEric Joyner {
11511031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
11521031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
11531031d839SEric Joyner 	struct i40e_hw		*hw = vsi->hw;
11541031d839SEric Joyner 	struct ixl_rx_queue	*que = vsi->rx_queues;
11551031d839SEric Joyner 
11561031d839SEric Joyner 	ixl_enable_intr0(hw);
11571031d839SEric Joyner 	/* Enable queue interrupts */
11581031d839SEric Joyner 	for (int i = 0; i < vsi->num_rx_queues; i++, que++)
11591031d839SEric Joyner 		/* TODO: Queue index parameter is probably wrong */
11601031d839SEric Joyner 		ixl_enable_queue(hw, que->rxr.me);
11611031d839SEric Joyner }
11621031d839SEric Joyner 
11631031d839SEric Joyner /*
11641031d839SEric Joyner  * Disable queue interrupts
11651031d839SEric Joyner  *
11661031d839SEric Joyner  * Other interrupt causes need to remain active.
11671031d839SEric Joyner  */
11681031d839SEric Joyner static void
ixl_if_disable_intr(if_ctx_t ctx)11691031d839SEric Joyner ixl_if_disable_intr(if_ctx_t ctx)
11701031d839SEric Joyner {
11711031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
11721031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
11731031d839SEric Joyner 	struct i40e_hw		*hw = vsi->hw;
11741031d839SEric Joyner 	struct ixl_rx_queue	*rx_que = vsi->rx_queues;
11751031d839SEric Joyner 
11761031d839SEric Joyner 	if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) {
11771031d839SEric Joyner 		for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++)
11781031d839SEric Joyner 			ixl_disable_queue(hw, rx_que->msix - 1);
11791031d839SEric Joyner 	} else {
11801031d839SEric Joyner 		// Set PFINT_LNKLST0 FIRSTQ_INDX to 0x7FF
11811031d839SEric Joyner 		// stops queues from triggering interrupts
11821031d839SEric Joyner 		wr32(hw, I40E_PFINT_LNKLST0, 0x7FF);
11831031d839SEric Joyner 	}
11841031d839SEric Joyner }
11851031d839SEric Joyner 
11861031d839SEric Joyner static int
ixl_if_rx_queue_intr_enable(if_ctx_t ctx,uint16_t rxqid)11871031d839SEric Joyner ixl_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid)
11881031d839SEric Joyner {
11891031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
11901031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
11911031d839SEric Joyner 	struct i40e_hw		*hw = vsi->hw;
11921031d839SEric Joyner 	struct ixl_rx_queue	*rx_que = &vsi->rx_queues[rxqid];
11931031d839SEric Joyner 
11941031d839SEric Joyner 	ixl_enable_queue(hw, rx_que->msix - 1);
11951031d839SEric Joyner 	return (0);
11961031d839SEric Joyner }
11971031d839SEric Joyner 
11981031d839SEric Joyner static int
ixl_if_tx_queue_intr_enable(if_ctx_t ctx,uint16_t txqid)11991031d839SEric Joyner ixl_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid)
12001031d839SEric Joyner {
12011031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
12021031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
12031031d839SEric Joyner 	struct i40e_hw *hw = vsi->hw;
12041031d839SEric Joyner 	struct ixl_tx_queue *tx_que = &vsi->tx_queues[txqid];
12051031d839SEric Joyner 
12061031d839SEric Joyner 	ixl_enable_queue(hw, tx_que->msix - 1);
12071031d839SEric Joyner 	return (0);
12081031d839SEric Joyner }
12091031d839SEric Joyner 
12101031d839SEric Joyner static int
ixl_if_tx_queues_alloc(if_ctx_t ctx,caddr_t * vaddrs,uint64_t * paddrs,int ntxqs,int ntxqsets)12111031d839SEric Joyner ixl_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets)
12121031d839SEric Joyner {
12131031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
12141031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
12151031d839SEric Joyner 	if_softc_ctx_t scctx = vsi->shared;
12161031d839SEric Joyner 	struct ixl_tx_queue *que;
12171031d839SEric Joyner 	int i, j, error = 0;
12181031d839SEric Joyner 
121977c1fcecSEric Joyner 	MPASS(scctx->isc_ntxqsets > 0);
12201031d839SEric Joyner 	MPASS(ntxqs == 1);
122177c1fcecSEric Joyner 	MPASS(scctx->isc_ntxqsets == ntxqsets);
12221031d839SEric Joyner 
12231031d839SEric Joyner 	/* Allocate queue structure memory */
12241031d839SEric Joyner 	if (!(vsi->tx_queues =
12251031d839SEric Joyner 	    (struct ixl_tx_queue *) malloc(sizeof(struct ixl_tx_queue) *ntxqsets, M_IXL, M_NOWAIT | M_ZERO))) {
12261031d839SEric Joyner 		device_printf(iflib_get_dev(ctx), "Unable to allocate TX ring memory\n");
12271031d839SEric Joyner 		return (ENOMEM);
12281031d839SEric Joyner 	}
12291031d839SEric Joyner 
12301031d839SEric Joyner 	for (i = 0, que = vsi->tx_queues; i < ntxqsets; i++, que++) {
12311031d839SEric Joyner 		struct tx_ring *txr = &que->txr;
12321031d839SEric Joyner 
12331031d839SEric Joyner 		txr->me = i;
12341031d839SEric Joyner 		que->vsi = vsi;
12351031d839SEric Joyner 
12361031d839SEric Joyner 		if (!vsi->enable_head_writeback) {
12371031d839SEric Joyner 			/* Allocate report status array */
12381031d839SEric Joyner 			if (!(txr->tx_rsq = malloc(sizeof(qidx_t) * scctx->isc_ntxd[0], M_IXL, M_NOWAIT))) {
12391031d839SEric Joyner 				device_printf(iflib_get_dev(ctx), "failed to allocate tx_rsq memory\n");
12401031d839SEric Joyner 				error = ENOMEM;
12411031d839SEric Joyner 				goto fail;
12421031d839SEric Joyner 			}
12431031d839SEric Joyner 			/* Init report status array */
12441031d839SEric Joyner 			for (j = 0; j < scctx->isc_ntxd[0]; j++)
12451031d839SEric Joyner 				txr->tx_rsq[j] = QIDX_INVALID;
12461031d839SEric Joyner 		}
12471031d839SEric Joyner 		/* get the virtual and physical address of the hardware queues */
12481031d839SEric Joyner 		txr->tail = I40E_QTX_TAIL(txr->me);
12491031d839SEric Joyner 		txr->tx_base = (struct i40e_tx_desc *)vaddrs[i * ntxqs];
12501031d839SEric Joyner 		txr->tx_paddr = paddrs[i * ntxqs];
12511031d839SEric Joyner 		txr->que = que;
12521031d839SEric Joyner 	}
12531031d839SEric Joyner 
12541031d839SEric Joyner 	return (0);
12551031d839SEric Joyner fail:
12561031d839SEric Joyner 	ixl_if_queues_free(ctx);
12571031d839SEric Joyner 	return (error);
12581031d839SEric Joyner }
12591031d839SEric Joyner 
12601031d839SEric Joyner static int
ixl_if_rx_queues_alloc(if_ctx_t ctx,caddr_t * vaddrs,uint64_t * paddrs,int nrxqs,int nrxqsets)12611031d839SEric Joyner ixl_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs, int nrxqsets)
12621031d839SEric Joyner {
12631031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
12641031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
12651031d839SEric Joyner 	struct ixl_rx_queue *que;
12661031d839SEric Joyner 	int i, error = 0;
12671031d839SEric Joyner 
126877c1fcecSEric Joyner #ifdef INVARIANTS
126977c1fcecSEric Joyner 	if_softc_ctx_t scctx = vsi->shared;
127077c1fcecSEric Joyner 	MPASS(scctx->isc_nrxqsets > 0);
12711031d839SEric Joyner 	MPASS(nrxqs == 1);
127277c1fcecSEric Joyner 	MPASS(scctx->isc_nrxqsets == nrxqsets);
127377c1fcecSEric Joyner #endif
12741031d839SEric Joyner 
12751031d839SEric Joyner 	/* Allocate queue structure memory */
12761031d839SEric Joyner 	if (!(vsi->rx_queues =
12771031d839SEric Joyner 	    (struct ixl_rx_queue *) malloc(sizeof(struct ixl_rx_queue) *
12781031d839SEric Joyner 	    nrxqsets, M_IXL, M_NOWAIT | M_ZERO))) {
12791031d839SEric Joyner 		device_printf(iflib_get_dev(ctx), "Unable to allocate RX ring memory\n");
12801031d839SEric Joyner 		error = ENOMEM;
12811031d839SEric Joyner 		goto fail;
12821031d839SEric Joyner 	}
12831031d839SEric Joyner 
12841031d839SEric Joyner 	for (i = 0, que = vsi->rx_queues; i < nrxqsets; i++, que++) {
12851031d839SEric Joyner 		struct rx_ring *rxr = &que->rxr;
12861031d839SEric Joyner 
12871031d839SEric Joyner 		rxr->me = i;
12881031d839SEric Joyner 		que->vsi = vsi;
12891031d839SEric Joyner 
12901031d839SEric Joyner 		/* get the virtual and physical address of the hardware queues */
12911031d839SEric Joyner 		rxr->tail = I40E_QRX_TAIL(rxr->me);
12921031d839SEric Joyner 		rxr->rx_base = (union i40e_rx_desc *)vaddrs[i * nrxqs];
12931031d839SEric Joyner 		rxr->rx_paddr = paddrs[i * nrxqs];
12941031d839SEric Joyner 		rxr->que = que;
12951031d839SEric Joyner 	}
12961031d839SEric Joyner 
12971031d839SEric Joyner 	return (0);
12981031d839SEric Joyner fail:
12991031d839SEric Joyner 	ixl_if_queues_free(ctx);
13001031d839SEric Joyner 	return (error);
13011031d839SEric Joyner }
13021031d839SEric Joyner 
13031031d839SEric Joyner static void
ixl_if_queues_free(if_ctx_t ctx)13041031d839SEric Joyner ixl_if_queues_free(if_ctx_t ctx)
13051031d839SEric Joyner {
13061031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
13071031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
13081031d839SEric Joyner 
130938bfc6deSSai Rajesh Tallamraju 	if (vsi->tx_queues != NULL && !vsi->enable_head_writeback) {
13101031d839SEric Joyner 		struct ixl_tx_queue *que;
13111031d839SEric Joyner 		int i = 0;
13121031d839SEric Joyner 
13131031d839SEric Joyner 		for (i = 0, que = vsi->tx_queues; i < vsi->num_tx_queues; i++, que++) {
13141031d839SEric Joyner 			struct tx_ring *txr = &que->txr;
13151031d839SEric Joyner 			if (txr->tx_rsq != NULL) {
13161031d839SEric Joyner 				free(txr->tx_rsq, M_IXL);
13171031d839SEric Joyner 				txr->tx_rsq = NULL;
13181031d839SEric Joyner 			}
13191031d839SEric Joyner 		}
13201031d839SEric Joyner 	}
13211031d839SEric Joyner 
13221031d839SEric Joyner 	if (vsi->tx_queues != NULL) {
13231031d839SEric Joyner 		free(vsi->tx_queues, M_IXL);
13241031d839SEric Joyner 		vsi->tx_queues = NULL;
13251031d839SEric Joyner 	}
13261031d839SEric Joyner 	if (vsi->rx_queues != NULL) {
13271031d839SEric Joyner 		free(vsi->rx_queues, M_IXL);
13281031d839SEric Joyner 		vsi->rx_queues = NULL;
13291031d839SEric Joyner 	}
1330b4a7ce06SEric Joyner 
1331b4a7ce06SEric Joyner 	if (!IXL_PF_IN_RECOVERY_MODE(pf))
1332b4a7ce06SEric Joyner 		sysctl_ctx_free(&vsi->sysctl_ctx);
13331031d839SEric Joyner }
13341031d839SEric Joyner 
13351031d839SEric Joyner void
ixl_update_link_status(struct ixl_pf * pf)13361031d839SEric Joyner ixl_update_link_status(struct ixl_pf *pf)
13371031d839SEric Joyner {
13381031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
1339c9da8d8bSEric Joyner 	struct i40e_hw *hw = &pf->hw;
13401031d839SEric Joyner 	u64 baudrate;
13411031d839SEric Joyner 
13421031d839SEric Joyner 	if (pf->link_up) {
13431031d839SEric Joyner 		if (vsi->link_active == FALSE) {
13441031d839SEric Joyner 			vsi->link_active = TRUE;
1345c9da8d8bSEric Joyner 			baudrate = ixl_max_aq_speed_to_value(hw->phy.link_info.link_speed);
13461031d839SEric Joyner 			iflib_link_state_change(vsi->ctx, LINK_STATE_UP, baudrate);
13471031d839SEric Joyner 			ixl_link_up_msg(pf);
13481031d839SEric Joyner #ifdef PCI_IOV
13491031d839SEric Joyner 			ixl_broadcast_link_state(pf);
13501031d839SEric Joyner #endif
13511031d839SEric Joyner 		}
13521031d839SEric Joyner 	} else { /* Link down */
13531031d839SEric Joyner 		if (vsi->link_active == TRUE) {
13541031d839SEric Joyner 			vsi->link_active = FALSE;
13551031d839SEric Joyner 			iflib_link_state_change(vsi->ctx, LINK_STATE_DOWN, 0);
13561031d839SEric Joyner #ifdef PCI_IOV
13571031d839SEric Joyner 			ixl_broadcast_link_state(pf);
13581031d839SEric Joyner #endif
13591031d839SEric Joyner 		}
13601031d839SEric Joyner 	}
13611031d839SEric Joyner }
13621031d839SEric Joyner 
136377c1fcecSEric Joyner static void
ixl_handle_lan_overflow_event(struct ixl_pf * pf,struct i40e_arq_event_info * e)136477c1fcecSEric Joyner ixl_handle_lan_overflow_event(struct ixl_pf *pf, struct i40e_arq_event_info *e)
136577c1fcecSEric Joyner {
136677c1fcecSEric Joyner 	device_t dev = pf->dev;
136777c1fcecSEric Joyner 	u32 rxq_idx, qtx_ctl;
136877c1fcecSEric Joyner 
136977c1fcecSEric Joyner 	rxq_idx = (e->desc.params.external.param0 & I40E_PRTDCB_RUPTQ_RXQNUM_MASK) >>
137077c1fcecSEric Joyner 	    I40E_PRTDCB_RUPTQ_RXQNUM_SHIFT;
137177c1fcecSEric Joyner 	qtx_ctl = e->desc.params.external.param1;
137277c1fcecSEric Joyner 
137377c1fcecSEric Joyner 	device_printf(dev, "LAN overflow event: global rxq_idx %d\n", rxq_idx);
137477c1fcecSEric Joyner 	device_printf(dev, "LAN overflow event: QTX_CTL 0x%08x\n", qtx_ctl);
137577c1fcecSEric Joyner }
137677c1fcecSEric Joyner 
13771031d839SEric Joyner static int
ixl_process_adminq(struct ixl_pf * pf,u16 * pending)13781031d839SEric Joyner ixl_process_adminq(struct ixl_pf *pf, u16 *pending)
13791031d839SEric Joyner {
13801031d839SEric Joyner 	enum i40e_status_code status = I40E_SUCCESS;
13811031d839SEric Joyner 	struct i40e_arq_event_info event;
13821031d839SEric Joyner 	struct i40e_hw *hw = &pf->hw;
13831031d839SEric Joyner 	device_t dev = pf->dev;
13841031d839SEric Joyner 	u16 opcode;
13851031d839SEric Joyner 	u32 loop = 0, reg;
13861031d839SEric Joyner 
13871031d839SEric Joyner 	event.buf_len = IXL_AQ_BUF_SZ;
13881031d839SEric Joyner 	event.msg_buf = malloc(event.buf_len, M_IXL, M_NOWAIT | M_ZERO);
13891031d839SEric Joyner 	if (!event.msg_buf) {
13901031d839SEric Joyner 		device_printf(dev, "%s: Unable to allocate memory for Admin"
13911031d839SEric Joyner 		    " Queue event!\n", __func__);
13921031d839SEric Joyner 		return (ENOMEM);
13931031d839SEric Joyner 	}
13941031d839SEric Joyner 
13951031d839SEric Joyner 	/* clean and process any events */
13961031d839SEric Joyner 	do {
13971031d839SEric Joyner 		status = i40e_clean_arq_element(hw, &event, pending);
13981031d839SEric Joyner 		if (status)
13991031d839SEric Joyner 			break;
14001031d839SEric Joyner 		opcode = LE16_TO_CPU(event.desc.opcode);
14011031d839SEric Joyner 		ixl_dbg(pf, IXL_DBG_AQ,
14021031d839SEric Joyner 		    "Admin Queue event: %#06x\n", opcode);
14031031d839SEric Joyner 		switch (opcode) {
14041031d839SEric Joyner 		case i40e_aqc_opc_get_link_status:
14051031d839SEric Joyner 			ixl_link_event(pf, &event);
14061031d839SEric Joyner 			break;
14071031d839SEric Joyner 		case i40e_aqc_opc_send_msg_to_pf:
14081031d839SEric Joyner #ifdef PCI_IOV
14091031d839SEric Joyner 			ixl_handle_vf_msg(pf, &event);
14101031d839SEric Joyner #endif
14111031d839SEric Joyner 			break;
14121031d839SEric Joyner 		/*
14131031d839SEric Joyner 		 * This should only occur on no-drop queues, which
14141031d839SEric Joyner 		 * aren't currently configured.
14151031d839SEric Joyner 		 */
14161031d839SEric Joyner 		case i40e_aqc_opc_event_lan_overflow:
141777c1fcecSEric Joyner 			ixl_handle_lan_overflow_event(pf, &event);
14181031d839SEric Joyner 			break;
14191031d839SEric Joyner 		default:
14201031d839SEric Joyner 			break;
14211031d839SEric Joyner 		}
14221031d839SEric Joyner 	} while (*pending && (loop++ < IXL_ADM_LIMIT));
14231031d839SEric Joyner 
14241031d839SEric Joyner 	free(event.msg_buf, M_IXL);
14251031d839SEric Joyner 
14261031d839SEric Joyner 	/* Re-enable admin queue interrupt cause */
14271031d839SEric Joyner 	reg = rd32(hw, I40E_PFINT_ICR0_ENA);
14281031d839SEric Joyner 	reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
14291031d839SEric Joyner 	wr32(hw, I40E_PFINT_ICR0_ENA, reg);
14301031d839SEric Joyner 
14311031d839SEric Joyner 	return (status);
14321031d839SEric Joyner }
14331031d839SEric Joyner 
14341031d839SEric Joyner static void
ixl_if_update_admin_status(if_ctx_t ctx)14351031d839SEric Joyner ixl_if_update_admin_status(if_ctx_t ctx)
14361031d839SEric Joyner {
14371031d839SEric Joyner 	struct ixl_pf	*pf = iflib_get_softc(ctx);
14381031d839SEric Joyner 	struct i40e_hw	*hw = &pf->hw;
14391031d839SEric Joyner 	u16		pending;
14401031d839SEric Joyner 
14417d4dceecSKrzysztof Galazka 	if (IXL_PF_IS_RESETTING(pf))
14421031d839SEric Joyner 		ixl_handle_empr_reset(pf);
14431031d839SEric Joyner 
1444b4a7ce06SEric Joyner 	/*
1445b4a7ce06SEric Joyner 	 * Admin Queue is shut down while handling reset.
1446b4a7ce06SEric Joyner 	 * Don't proceed if it hasn't been re-initialized
1447b4a7ce06SEric Joyner 	 * e.g due to an issue with new FW.
1448b4a7ce06SEric Joyner 	 */
1449b4a7ce06SEric Joyner 	if (!i40e_check_asq_alive(&pf->hw))
1450b4a7ce06SEric Joyner 		return;
1451b4a7ce06SEric Joyner 
1452b8f51b8cSPiotr Kubaj 	if (ixl_test_state(&pf->state, IXL_STATE_MDD_PENDING))
14531031d839SEric Joyner 		ixl_handle_mdd_event(pf);
14541031d839SEric Joyner 
14551031d839SEric Joyner 	ixl_process_adminq(pf, &pending);
14561031d839SEric Joyner 	ixl_update_link_status(pf);
14571031d839SEric Joyner 
14581031d839SEric Joyner 	/*
14591031d839SEric Joyner 	 * If there are still messages to process, reschedule ourselves.
14601031d839SEric Joyner 	 * Otherwise, re-enable our interrupt and go to sleep.
14611031d839SEric Joyner 	 */
14621031d839SEric Joyner 	if (pending > 0)
14631031d839SEric Joyner 		iflib_admin_intr_deferred(ctx);
14641031d839SEric Joyner 	else
14651031d839SEric Joyner 		ixl_enable_intr0(hw);
14661031d839SEric Joyner }
14671031d839SEric Joyner 
14681031d839SEric Joyner static void
ixl_if_multi_set(if_ctx_t ctx)14691031d839SEric Joyner ixl_if_multi_set(if_ctx_t ctx)
14701031d839SEric Joyner {
14711031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
14721031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
14731031d839SEric Joyner 	struct i40e_hw *hw = vsi->hw;
14747d4dceecSKrzysztof Galazka 	int mcnt;
14751031d839SEric Joyner 
14761031d839SEric Joyner 	IOCTL_DEBUGOUT("ixl_if_multi_set: begin");
14771031d839SEric Joyner 
147877c1fcecSEric Joyner 	/* Delete filters for removed multicast addresses */
14797d4dceecSKrzysztof Galazka 	ixl_del_multi(vsi, false);
14801031d839SEric Joyner 
14817d4dceecSKrzysztof Galazka 	mcnt = min(if_llmaddr_count(iflib_get_ifp(ctx)), MAX_MULTICAST_ADDR);
14821031d839SEric Joyner 	if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) {
14831031d839SEric Joyner 		i40e_aq_set_vsi_multicast_promiscuous(hw,
14841031d839SEric Joyner 		    vsi->seid, TRUE, NULL);
14857d4dceecSKrzysztof Galazka 		ixl_del_multi(vsi, true);
14861031d839SEric Joyner 		return;
14871031d839SEric Joyner 	}
14881031d839SEric Joyner 
14897d4dceecSKrzysztof Galazka 	ixl_add_multi(vsi);
14901031d839SEric Joyner 	IOCTL_DEBUGOUT("ixl_if_multi_set: end");
14911031d839SEric Joyner }
14921031d839SEric Joyner 
14931031d839SEric Joyner static int
ixl_if_mtu_set(if_ctx_t ctx,uint32_t mtu)14941031d839SEric Joyner ixl_if_mtu_set(if_ctx_t ctx, uint32_t mtu)
14951031d839SEric Joyner {
14961031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
14971031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
14981031d839SEric Joyner 
14991031d839SEric Joyner 	IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)");
15001031d839SEric Joyner 	if (mtu > IXL_MAX_FRAME - ETHER_HDR_LEN - ETHER_CRC_LEN -
15011031d839SEric Joyner 		ETHER_VLAN_ENCAP_LEN)
15021031d839SEric Joyner 		return (EINVAL);
15031031d839SEric Joyner 
15041031d839SEric Joyner 	vsi->shared->isc_max_frame_size = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN +
15051031d839SEric Joyner 		ETHER_VLAN_ENCAP_LEN;
15061031d839SEric Joyner 
15071031d839SEric Joyner 	return (0);
15081031d839SEric Joyner }
15091031d839SEric Joyner 
15101031d839SEric Joyner static void
ixl_if_media_status(if_ctx_t ctx,struct ifmediareq * ifmr)15111031d839SEric Joyner ixl_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr)
15121031d839SEric Joyner {
15131031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
15141031d839SEric Joyner 	struct i40e_hw  *hw = &pf->hw;
15151031d839SEric Joyner 
15161031d839SEric Joyner 	INIT_DEBUGOUT("ixl_media_status: begin");
15171031d839SEric Joyner 
15181031d839SEric Joyner 	ifmr->ifm_status = IFM_AVALID;
15191031d839SEric Joyner 	ifmr->ifm_active = IFM_ETHER;
15201031d839SEric Joyner 
15211031d839SEric Joyner 	if (!pf->link_up) {
15221031d839SEric Joyner 		return;
15231031d839SEric Joyner 	}
15241031d839SEric Joyner 
15251031d839SEric Joyner 	ifmr->ifm_status |= IFM_ACTIVE;
15261031d839SEric Joyner 	/* Hardware is always full-duplex */
15271031d839SEric Joyner 	ifmr->ifm_active |= IFM_FDX;
15281031d839SEric Joyner 
15291031d839SEric Joyner 	switch (hw->phy.link_info.phy_type) {
15301031d839SEric Joyner 		/* 100 M */
15311031d839SEric Joyner 		case I40E_PHY_TYPE_100BASE_TX:
15321031d839SEric Joyner 			ifmr->ifm_active |= IFM_100_TX;
15331031d839SEric Joyner 			break;
15341031d839SEric Joyner 		/* 1 G */
15351031d839SEric Joyner 		case I40E_PHY_TYPE_1000BASE_T:
15361031d839SEric Joyner 			ifmr->ifm_active |= IFM_1000_T;
15371031d839SEric Joyner 			break;
15381031d839SEric Joyner 		case I40E_PHY_TYPE_1000BASE_SX:
15391031d839SEric Joyner 			ifmr->ifm_active |= IFM_1000_SX;
15401031d839SEric Joyner 			break;
15411031d839SEric Joyner 		case I40E_PHY_TYPE_1000BASE_LX:
15421031d839SEric Joyner 			ifmr->ifm_active |= IFM_1000_LX;
15431031d839SEric Joyner 			break;
15441031d839SEric Joyner 		case I40E_PHY_TYPE_1000BASE_T_OPTICAL:
15451031d839SEric Joyner 			ifmr->ifm_active |= IFM_1000_T;
15461031d839SEric Joyner 			break;
15472984a8ddSEric Joyner 		/* 2.5 G */
1548abf77452SKrzysztof Galazka 		case I40E_PHY_TYPE_2_5GBASE_T_LINK_STATUS:
15492984a8ddSEric Joyner 			ifmr->ifm_active |= IFM_2500_T;
15502984a8ddSEric Joyner 			break;
15512984a8ddSEric Joyner 		/* 5 G */
1552abf77452SKrzysztof Galazka 		case I40E_PHY_TYPE_5GBASE_T_LINK_STATUS:
15532984a8ddSEric Joyner 			ifmr->ifm_active |= IFM_5000_T;
15542984a8ddSEric Joyner 			break;
15551031d839SEric Joyner 		/* 10 G */
15561031d839SEric Joyner 		case I40E_PHY_TYPE_10GBASE_SFPP_CU:
15571031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_TWINAX;
15581031d839SEric Joyner 			break;
15591031d839SEric Joyner 		case I40E_PHY_TYPE_10GBASE_SR:
15601031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_SR;
15611031d839SEric Joyner 			break;
15621031d839SEric Joyner 		case I40E_PHY_TYPE_10GBASE_LR:
15631031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_LR;
15641031d839SEric Joyner 			break;
15651031d839SEric Joyner 		case I40E_PHY_TYPE_10GBASE_T:
15661031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_T;
15671031d839SEric Joyner 			break;
15681031d839SEric Joyner 		case I40E_PHY_TYPE_XAUI:
15691031d839SEric Joyner 		case I40E_PHY_TYPE_XFI:
15701031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_TWINAX;
15711031d839SEric Joyner 			break;
15721031d839SEric Joyner 		case I40E_PHY_TYPE_10GBASE_AOC:
15731031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_AOC;
15741031d839SEric Joyner 			break;
15751031d839SEric Joyner 		/* 25 G */
15761031d839SEric Joyner 		case I40E_PHY_TYPE_25GBASE_KR:
15771031d839SEric Joyner 			ifmr->ifm_active |= IFM_25G_KR;
15781031d839SEric Joyner 			break;
15791031d839SEric Joyner 		case I40E_PHY_TYPE_25GBASE_CR:
15801031d839SEric Joyner 			ifmr->ifm_active |= IFM_25G_CR;
15811031d839SEric Joyner 			break;
15821031d839SEric Joyner 		case I40E_PHY_TYPE_25GBASE_SR:
15831031d839SEric Joyner 			ifmr->ifm_active |= IFM_25G_SR;
15841031d839SEric Joyner 			break;
15851031d839SEric Joyner 		case I40E_PHY_TYPE_25GBASE_LR:
15861031d839SEric Joyner 			ifmr->ifm_active |= IFM_25G_LR;
15871031d839SEric Joyner 			break;
15881031d839SEric Joyner 		case I40E_PHY_TYPE_25GBASE_AOC:
15891031d839SEric Joyner 			ifmr->ifm_active |= IFM_25G_AOC;
15901031d839SEric Joyner 			break;
15911031d839SEric Joyner 		case I40E_PHY_TYPE_25GBASE_ACC:
15921031d839SEric Joyner 			ifmr->ifm_active |= IFM_25G_ACC;
15931031d839SEric Joyner 			break;
15941031d839SEric Joyner 		/* 40 G */
15951031d839SEric Joyner 		case I40E_PHY_TYPE_40GBASE_CR4:
15961031d839SEric Joyner 		case I40E_PHY_TYPE_40GBASE_CR4_CU:
15971031d839SEric Joyner 			ifmr->ifm_active |= IFM_40G_CR4;
15981031d839SEric Joyner 			break;
15991031d839SEric Joyner 		case I40E_PHY_TYPE_40GBASE_SR4:
16001031d839SEric Joyner 			ifmr->ifm_active |= IFM_40G_SR4;
16011031d839SEric Joyner 			break;
16021031d839SEric Joyner 		case I40E_PHY_TYPE_40GBASE_LR4:
16031031d839SEric Joyner 			ifmr->ifm_active |= IFM_40G_LR4;
16041031d839SEric Joyner 			break;
16051031d839SEric Joyner 		case I40E_PHY_TYPE_XLAUI:
16061031d839SEric Joyner 			ifmr->ifm_active |= IFM_OTHER;
16071031d839SEric Joyner 			break;
16081031d839SEric Joyner 		case I40E_PHY_TYPE_1000BASE_KX:
16091031d839SEric Joyner 			ifmr->ifm_active |= IFM_1000_KX;
16101031d839SEric Joyner 			break;
16111031d839SEric Joyner 		case I40E_PHY_TYPE_SGMII:
16121031d839SEric Joyner 			ifmr->ifm_active |= IFM_1000_SGMII;
16131031d839SEric Joyner 			break;
16141031d839SEric Joyner 		/* ERJ: What's the difference between these? */
16151031d839SEric Joyner 		case I40E_PHY_TYPE_10GBASE_CR1_CU:
16161031d839SEric Joyner 		case I40E_PHY_TYPE_10GBASE_CR1:
16171031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_CR1;
16181031d839SEric Joyner 			break;
16191031d839SEric Joyner 		case I40E_PHY_TYPE_10GBASE_KX4:
16201031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_KX4;
16211031d839SEric Joyner 			break;
16221031d839SEric Joyner 		case I40E_PHY_TYPE_10GBASE_KR:
16231031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_KR;
16241031d839SEric Joyner 			break;
16251031d839SEric Joyner 		case I40E_PHY_TYPE_SFI:
16261031d839SEric Joyner 			ifmr->ifm_active |= IFM_10G_SFI;
16271031d839SEric Joyner 			break;
16281031d839SEric Joyner 		/* Our single 20G media type */
16291031d839SEric Joyner 		case I40E_PHY_TYPE_20GBASE_KR2:
16301031d839SEric Joyner 			ifmr->ifm_active |= IFM_20G_KR2;
16311031d839SEric Joyner 			break;
16321031d839SEric Joyner 		case I40E_PHY_TYPE_40GBASE_KR4:
16331031d839SEric Joyner 			ifmr->ifm_active |= IFM_40G_KR4;
16341031d839SEric Joyner 			break;
16351031d839SEric Joyner 		case I40E_PHY_TYPE_XLPPI:
16361031d839SEric Joyner 		case I40E_PHY_TYPE_40GBASE_AOC:
16371031d839SEric Joyner 			ifmr->ifm_active |= IFM_40G_XLPPI;
16381031d839SEric Joyner 			break;
16391031d839SEric Joyner 		/* Unknown to driver */
16401031d839SEric Joyner 		default:
16411031d839SEric Joyner 			ifmr->ifm_active |= IFM_UNKNOWN;
16421031d839SEric Joyner 			break;
16431031d839SEric Joyner 	}
16441031d839SEric Joyner 	/* Report flow control status as well */
16451031d839SEric Joyner 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
16461031d839SEric Joyner 		ifmr->ifm_active |= IFM_ETH_TXPAUSE;
16471031d839SEric Joyner 	if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
16481031d839SEric Joyner 		ifmr->ifm_active |= IFM_ETH_RXPAUSE;
16491031d839SEric Joyner }
16501031d839SEric Joyner 
16511031d839SEric Joyner static int
ixl_if_media_change(if_ctx_t ctx)16521031d839SEric Joyner ixl_if_media_change(if_ctx_t ctx)
16531031d839SEric Joyner {
16541031d839SEric Joyner 	struct ifmedia *ifm = iflib_get_media(ctx);
16551031d839SEric Joyner 
16561031d839SEric Joyner 	INIT_DEBUGOUT("ixl_media_change: begin");
16571031d839SEric Joyner 
16581031d839SEric Joyner 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
16591031d839SEric Joyner 		return (EINVAL);
16601031d839SEric Joyner 
16611031d839SEric Joyner 	if_printf(iflib_get_ifp(ctx), "Media change is not supported.\n");
16621031d839SEric Joyner 	return (ENODEV);
16631031d839SEric Joyner }
16641031d839SEric Joyner 
16651031d839SEric Joyner static int
ixl_if_promisc_set(if_ctx_t ctx,int flags)16661031d839SEric Joyner ixl_if_promisc_set(if_ctx_t ctx, int flags)
16671031d839SEric Joyner {
16681031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
16691031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
1670402810d3SJustin Hibbits 	if_t ifp = iflib_get_ifp(ctx);
16711031d839SEric Joyner 	struct i40e_hw	*hw = vsi->hw;
16721031d839SEric Joyner 	int		err;
16731031d839SEric Joyner 	bool		uni = FALSE, multi = FALSE;
16741031d839SEric Joyner 
16751031d839SEric Joyner 	if (flags & IFF_PROMISC)
16761031d839SEric Joyner 		uni = multi = TRUE;
1677ba76aa63SGleb Smirnoff 	else if (flags & IFF_ALLMULTI || if_llmaddr_count(ifp) >=
1678ba76aa63SGleb Smirnoff 	    MAX_MULTICAST_ADDR)
16791031d839SEric Joyner 		multi = TRUE;
16801031d839SEric Joyner 
16811031d839SEric Joyner 	err = i40e_aq_set_vsi_unicast_promiscuous(hw,
16821031d839SEric Joyner 	    vsi->seid, uni, NULL, true);
16831031d839SEric Joyner 	if (err)
16841031d839SEric Joyner 		return (err);
16851031d839SEric Joyner 	err = i40e_aq_set_vsi_multicast_promiscuous(hw,
16861031d839SEric Joyner 	    vsi->seid, multi, NULL);
16871031d839SEric Joyner 	return (err);
16881031d839SEric Joyner }
16891031d839SEric Joyner 
16901031d839SEric Joyner static void
ixl_if_timer(if_ctx_t ctx,uint16_t qid)16911031d839SEric Joyner ixl_if_timer(if_ctx_t ctx, uint16_t qid)
16921031d839SEric Joyner {
1693b4a7ce06SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
1694b4a7ce06SEric Joyner 
16951031d839SEric Joyner 	if (qid != 0)
16961031d839SEric Joyner 		return;
16971031d839SEric Joyner 
1698b4a7ce06SEric Joyner 	ixl_update_stats_counters(pf);
16991031d839SEric Joyner }
17001031d839SEric Joyner 
17011031d839SEric Joyner static void
ixl_if_vlan_register(if_ctx_t ctx,u16 vtag)17021031d839SEric Joyner ixl_if_vlan_register(if_ctx_t ctx, u16 vtag)
17031031d839SEric Joyner {
17041031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
17051031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
17061031d839SEric Joyner 	struct i40e_hw	*hw = vsi->hw;
17077d4dceecSKrzysztof Galazka 	if_t ifp = iflib_get_ifp(ctx);
17081031d839SEric Joyner 
17091031d839SEric Joyner 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
17101031d839SEric Joyner 		return;
17111031d839SEric Joyner 
17127d4dceecSKrzysztof Galazka 	/*
17137d4dceecSKrzysztof Galazka 	 * Keep track of registered VLANS to know what
17147d4dceecSKrzysztof Galazka 	 * filters have to be configured when VLAN_HWFILTER
17157d4dceecSKrzysztof Galazka 	 * capability is enabled.
17167d4dceecSKrzysztof Galazka 	 */
17171031d839SEric Joyner 	++vsi->num_vlans;
17187d4dceecSKrzysztof Galazka 	bit_set(vsi->vlans_map, vtag);
17197d4dceecSKrzysztof Galazka 
17207d4dceecSKrzysztof Galazka 	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
17217d4dceecSKrzysztof Galazka 		return;
17227d4dceecSKrzysztof Galazka 
17237d4dceecSKrzysztof Galazka 	if (vsi->num_vlans < IXL_MAX_VLAN_FILTERS)
17241031d839SEric Joyner 		ixl_add_filter(vsi, hw->mac.addr, vtag);
17257d4dceecSKrzysztof Galazka 	else if (vsi->num_vlans == IXL_MAX_VLAN_FILTERS) {
17267d4dceecSKrzysztof Galazka 		/*
17277d4dceecSKrzysztof Galazka 		 * There is not enough HW resources to add filters
17287d4dceecSKrzysztof Galazka 		 * for all registered VLANs. Re-configure filtering
17297d4dceecSKrzysztof Galazka 		 * to allow reception of all expected traffic.
17307d4dceecSKrzysztof Galazka 		 */
17317d4dceecSKrzysztof Galazka 		device_printf(vsi->dev,
17327d4dceecSKrzysztof Galazka 		    "Not enough HW filters for all VLANs. VLAN HW filtering disabled");
17337d4dceecSKrzysztof Galazka 		ixl_del_all_vlan_filters(vsi, hw->mac.addr);
17347d4dceecSKrzysztof Galazka 		ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
17357d4dceecSKrzysztof Galazka 	}
17361031d839SEric Joyner }
17371031d839SEric Joyner 
17381031d839SEric Joyner static void
ixl_if_vlan_unregister(if_ctx_t ctx,u16 vtag)17391031d839SEric Joyner ixl_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
17401031d839SEric Joyner {
17411031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
17421031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
17431031d839SEric Joyner 	struct i40e_hw	*hw = vsi->hw;
17447d4dceecSKrzysztof Galazka 	if_t ifp = iflib_get_ifp(ctx);
17451031d839SEric Joyner 
17461031d839SEric Joyner 	if ((vtag == 0) || (vtag > 4095))	/* Invalid */
17471031d839SEric Joyner 		return;
17481031d839SEric Joyner 
17491031d839SEric Joyner 	--vsi->num_vlans;
17507d4dceecSKrzysztof Galazka 	bit_clear(vsi->vlans_map, vtag);
17517d4dceecSKrzysztof Galazka 
17527d4dceecSKrzysztof Galazka 	if ((if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER) == 0)
17537d4dceecSKrzysztof Galazka 		return;
17547d4dceecSKrzysztof Galazka 
17551d02c6b1SKrzysztof Galazka 	/* One filter is used for untagged frames */
17561d02c6b1SKrzysztof Galazka 	if (vsi->num_vlans < IXL_MAX_VLAN_FILTERS - 1)
17571031d839SEric Joyner 		ixl_del_filter(vsi, hw->mac.addr, vtag);
17581d02c6b1SKrzysztof Galazka 	else if (vsi->num_vlans == IXL_MAX_VLAN_FILTERS - 1) {
17597d4dceecSKrzysztof Galazka 		ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY);
17607d4dceecSKrzysztof Galazka 		ixl_add_vlan_filters(vsi, hw->mac.addr);
17617d4dceecSKrzysztof Galazka 	}
17621031d839SEric Joyner }
17631031d839SEric Joyner 
17641031d839SEric Joyner static uint64_t
ixl_if_get_counter(if_ctx_t ctx,ift_counter cnt)17651031d839SEric Joyner ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt)
17661031d839SEric Joyner {
17671031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
17681031d839SEric Joyner 	struct ixl_vsi *vsi = &pf->vsi;
17691031d839SEric Joyner 	if_t ifp = iflib_get_ifp(ctx);
17701031d839SEric Joyner 
17711031d839SEric Joyner 	switch (cnt) {
17721031d839SEric Joyner 	case IFCOUNTER_IPACKETS:
17731031d839SEric Joyner 		return (vsi->ipackets);
17741031d839SEric Joyner 	case IFCOUNTER_IERRORS:
17751031d839SEric Joyner 		return (vsi->ierrors);
17761031d839SEric Joyner 	case IFCOUNTER_OPACKETS:
17771031d839SEric Joyner 		return (vsi->opackets);
17781031d839SEric Joyner 	case IFCOUNTER_OERRORS:
17791031d839SEric Joyner 		return (vsi->oerrors);
17801031d839SEric Joyner 	case IFCOUNTER_COLLISIONS:
17811031d839SEric Joyner 		/* Collisions are by standard impossible in 40G/10G Ethernet */
17821031d839SEric Joyner 		return (0);
17831031d839SEric Joyner 	case IFCOUNTER_IBYTES:
17841031d839SEric Joyner 		return (vsi->ibytes);
17851031d839SEric Joyner 	case IFCOUNTER_OBYTES:
17861031d839SEric Joyner 		return (vsi->obytes);
17871031d839SEric Joyner 	case IFCOUNTER_IMCASTS:
17881031d839SEric Joyner 		return (vsi->imcasts);
17891031d839SEric Joyner 	case IFCOUNTER_OMCASTS:
17901031d839SEric Joyner 		return (vsi->omcasts);
17911031d839SEric Joyner 	case IFCOUNTER_IQDROPS:
17921031d839SEric Joyner 		return (vsi->iqdrops);
17931031d839SEric Joyner 	case IFCOUNTER_OQDROPS:
17941031d839SEric Joyner 		return (vsi->oqdrops);
17951031d839SEric Joyner 	case IFCOUNTER_NOPROTO:
17961031d839SEric Joyner 		return (vsi->noproto);
17971031d839SEric Joyner 	default:
17981031d839SEric Joyner 		return (if_get_counter_default(ifp, cnt));
17991031d839SEric Joyner 	}
18001031d839SEric Joyner }
18011031d839SEric Joyner 
180277c1fcecSEric Joyner #ifdef PCI_IOV
18031031d839SEric Joyner static void
ixl_if_vflr_handle(if_ctx_t ctx)18041031d839SEric Joyner ixl_if_vflr_handle(if_ctx_t ctx)
18051031d839SEric Joyner {
180677c1fcecSEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
18071031d839SEric Joyner 
180877c1fcecSEric Joyner 	ixl_handle_vflr(pf);
18091031d839SEric Joyner }
181077c1fcecSEric Joyner #endif
18111031d839SEric Joyner 
18121031d839SEric Joyner static int
ixl_if_i2c_req(if_ctx_t ctx,struct ifi2creq * req)18131031d839SEric Joyner ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req)
18141031d839SEric Joyner {
18151031d839SEric Joyner 	struct ixl_pf		*pf = iflib_get_softc(ctx);
18161031d839SEric Joyner 
18171031d839SEric Joyner 	if (pf->read_i2c_byte == NULL)
18181031d839SEric Joyner 		return (EINVAL);
18191031d839SEric Joyner 
18201031d839SEric Joyner 	for (int i = 0; i < req->len; i++)
18211031d839SEric Joyner 		if (pf->read_i2c_byte(pf, req->offset + i,
18221031d839SEric Joyner 		    req->dev_addr, &req->data[i]))
18231031d839SEric Joyner 			return (EIO);
18241031d839SEric Joyner 	return (0);
18251031d839SEric Joyner }
18261031d839SEric Joyner 
18271031d839SEric Joyner static int
ixl_if_priv_ioctl(if_ctx_t ctx,u_long command,caddr_t data)18281031d839SEric Joyner ixl_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data)
18291031d839SEric Joyner {
18301031d839SEric Joyner 	struct ixl_pf *pf = iflib_get_softc(ctx);
18311031d839SEric Joyner 	struct ifdrv *ifd = (struct ifdrv *)data;
18321031d839SEric Joyner 	int error = 0;
18331031d839SEric Joyner 
1834ab43ce7aSEric Joyner 	/*
1835ab43ce7aSEric Joyner 	 * The iflib_if_ioctl forwards SIOCxDRVSPEC and SIOGPRIVATE_0 without
1836ab43ce7aSEric Joyner 	 * performing privilege checks. It is important that this function
1837ab43ce7aSEric Joyner 	 * perform the necessary checks for commands which should only be
1838ab43ce7aSEric Joyner 	 * executed by privileged threads.
1839ab43ce7aSEric Joyner 	 */
1840ab43ce7aSEric Joyner 
1841ab43ce7aSEric Joyner 	switch(command) {
1842ab43ce7aSEric Joyner 	case SIOCGDRVSPEC:
1843ab43ce7aSEric Joyner 	case SIOCSDRVSPEC:
18441031d839SEric Joyner 		/* NVM update command */
1845ab43ce7aSEric Joyner 		if (ifd->ifd_cmd == I40E_NVM_ACCESS) {
1846ab43ce7aSEric Joyner 			error = priv_check(curthread, PRIV_DRIVER);
1847ab43ce7aSEric Joyner 			if (error)
1848ab43ce7aSEric Joyner 				break;
18491031d839SEric Joyner 			error = ixl_handle_nvmupd_cmd(pf, ifd);
1850ab43ce7aSEric Joyner 		} else {
18511031d839SEric Joyner 			error = EINVAL;
1852ab43ce7aSEric Joyner 		}
1853ab43ce7aSEric Joyner 		break;
1854ab43ce7aSEric Joyner 	default:
1855ab43ce7aSEric Joyner 		error = EOPNOTSUPP;
1856ab43ce7aSEric Joyner 	}
18571031d839SEric Joyner 
18581031d839SEric Joyner 	return (error);
18591031d839SEric Joyner }
18601031d839SEric Joyner 
1861cf150917SEric Joyner /* ixl_if_needs_restart - Tell iflib when the driver needs to be reinitialized
1862cf150917SEric Joyner  * @ctx: iflib context
1863cf150917SEric Joyner  * @event: event code to check
1864cf150917SEric Joyner  *
1865cf150917SEric Joyner  * Defaults to returning false for every event.
1866cf150917SEric Joyner  *
1867cf150917SEric Joyner  * @returns true if iflib needs to reinit the interface, false otherwise
1868cf150917SEric Joyner  */
1869cf150917SEric Joyner static bool
ixl_if_needs_restart(if_ctx_t ctx __unused,enum iflib_restart_event event)1870cf150917SEric Joyner ixl_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event)
1871cf150917SEric Joyner {
1872cf150917SEric Joyner 	switch (event) {
1873cf150917SEric Joyner 	case IFLIB_RESTART_VLAN_CONFIG:
1874cf150917SEric Joyner 	default:
1875cf150917SEric Joyner 		return (false);
1876cf150917SEric Joyner 	}
1877cf150917SEric Joyner }
1878cf150917SEric Joyner 
18791031d839SEric Joyner /*
18801031d839SEric Joyner  * Sanity check and save off tunable values.
18811031d839SEric Joyner  */
18821031d839SEric Joyner static void
ixl_save_pf_tunables(struct ixl_pf * pf)18831031d839SEric Joyner ixl_save_pf_tunables(struct ixl_pf *pf)
18841031d839SEric Joyner {
18851031d839SEric Joyner 	device_t dev = pf->dev;
18861031d839SEric Joyner 
18871031d839SEric Joyner 	/* Save tunable information */
1888b4a7ce06SEric Joyner #ifdef IXL_DEBUG_FC
18891031d839SEric Joyner 	pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter;
1890b4a7ce06SEric Joyner #endif
1891b4a7ce06SEric Joyner #ifdef IXL_DEBUG
1892b4a7ce06SEric Joyner 	pf->recovery_mode = ixl_debug_recovery_mode;
1893b4a7ce06SEric Joyner #endif
18941031d839SEric Joyner 	pf->dbg_mask = ixl_core_debug_mask;
18951031d839SEric Joyner 	pf->hw.debug_mask = ixl_shared_debug_mask;
18961031d839SEric Joyner 	pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback);
189777c1fcecSEric Joyner 	pf->enable_vf_loopback = !!(ixl_enable_vf_loopback);
18981031d839SEric Joyner #if 0
18991031d839SEric Joyner 	pf->dynamic_rx_itr = ixl_dynamic_rx_itr;
19001031d839SEric Joyner 	pf->dynamic_tx_itr = ixl_dynamic_tx_itr;
19011031d839SEric Joyner #endif
19021031d839SEric Joyner 
19031031d839SEric Joyner 	if (ixl_i2c_access_method > 3 || ixl_i2c_access_method < 0)
19041031d839SEric Joyner 		pf->i2c_access_method = 0;
19051031d839SEric Joyner 	else
19061031d839SEric Joyner 		pf->i2c_access_method = ixl_i2c_access_method;
19071031d839SEric Joyner 
19081031d839SEric Joyner 	if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) {
19091031d839SEric Joyner 		device_printf(dev, "Invalid tx_itr value of %d set!\n",
19101031d839SEric Joyner 		    ixl_tx_itr);
19111031d839SEric Joyner 		device_printf(dev, "tx_itr must be between %d and %d, "
19121031d839SEric Joyner 		    "inclusive\n",
19131031d839SEric Joyner 		    0, IXL_MAX_ITR);
19141031d839SEric Joyner 		device_printf(dev, "Using default value of %d instead\n",
19151031d839SEric Joyner 		    IXL_ITR_4K);
19161031d839SEric Joyner 		pf->tx_itr = IXL_ITR_4K;
19171031d839SEric Joyner 	} else
19181031d839SEric Joyner 		pf->tx_itr = ixl_tx_itr;
19191031d839SEric Joyner 
19201031d839SEric Joyner 	if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) {
19211031d839SEric Joyner 		device_printf(dev, "Invalid rx_itr value of %d set!\n",
19221031d839SEric Joyner 		    ixl_rx_itr);
19231031d839SEric Joyner 		device_printf(dev, "rx_itr must be between %d and %d, "
19241031d839SEric Joyner 		    "inclusive\n",
19251031d839SEric Joyner 		    0, IXL_MAX_ITR);
19261031d839SEric Joyner 		device_printf(dev, "Using default value of %d instead\n",
19271031d839SEric Joyner 		    IXL_ITR_8K);
19281031d839SEric Joyner 		pf->rx_itr = IXL_ITR_8K;
19291031d839SEric Joyner 	} else
19301031d839SEric Joyner 		pf->rx_itr = ixl_rx_itr;
193120a52706SKrzysztof Galazka 
193220a52706SKrzysztof Galazka 	pf->fc = -1;
193320a52706SKrzysztof Galazka 	if (ixl_flow_control != -1) {
193420a52706SKrzysztof Galazka 		if (ixl_flow_control < 0 || ixl_flow_control > 3) {
193520a52706SKrzysztof Galazka 			device_printf(dev,
193620a52706SKrzysztof Galazka 			    "Invalid flow_control value of %d set!\n",
193720a52706SKrzysztof Galazka 			    ixl_flow_control);
193820a52706SKrzysztof Galazka 			device_printf(dev,
193920a52706SKrzysztof Galazka 			    "flow_control must be between %d and %d, "
194020a52706SKrzysztof Galazka 			    "inclusive\n", 0, 3);
194120a52706SKrzysztof Galazka 			device_printf(dev,
194220a52706SKrzysztof Galazka 			    "Using default configuration instead\n");
194320a52706SKrzysztof Galazka 		} else
194420a52706SKrzysztof Galazka 			pf->fc = ixl_flow_control;
194520a52706SKrzysztof Galazka 	}
19461031d839SEric Joyner }
19471031d839SEric Joyner 
1948