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 /*$FreeBSD$*/ 3461ae650dSJack F Vogel 3561ae650dSJack F Vogel #include "ixl.h" 3661ae650dSJack F Vogel #include "ixl_pf.h" 3761ae650dSJack F Vogel 38cb6b8299SEric Joyner #ifdef IXL_IW 39cb6b8299SEric Joyner #include "ixl_iw.h" 40cb6b8299SEric Joyner #include "ixl_iw_int.h" 41cb6b8299SEric Joyner #endif 42cb6b8299SEric Joyner 434294f337SSean Bruno #ifdef PCI_IOV 444294f337SSean Bruno #include "ixl_pf_iov.h" 45dcd7b3b2SJack F Vogel #endif 46dcd7b3b2SJack F Vogel 4761ae650dSJack F Vogel /********************************************************************* 4861ae650dSJack F Vogel * Driver version 4961ae650dSJack F Vogel *********************************************************************/ 50f4cc2d17SEric Joyner #define IXL_DRIVER_VERSION_MAJOR 2 51f4cc2d17SEric Joyner #define IXL_DRIVER_VERSION_MINOR 0 52f4cc2d17SEric Joyner #define IXL_DRIVER_VERSION_BUILD 0 53ceebc2f3SEric Joyner 541031d839SEric Joyner #define IXL_DRIVER_VERSION_STRING \ 551031d839SEric Joyner __XSTRING(IXL_DRIVER_VERSION_MAJOR) "." \ 561031d839SEric Joyner __XSTRING(IXL_DRIVER_VERSION_MINOR) "." \ 57f4cc2d17SEric Joyner __XSTRING(IXL_DRIVER_VERSION_BUILD) "-k" 5861ae650dSJack F Vogel 5961ae650dSJack F Vogel /********************************************************************* 6061ae650dSJack F Vogel * PCI Device ID Table 6161ae650dSJack F Vogel * 6261ae650dSJack F Vogel * Used by probe to select devices to load on 6361ae650dSJack F Vogel * 641031d839SEric Joyner * ( Vendor ID, Device ID, Branding String ) 6561ae650dSJack F Vogel *********************************************************************/ 6661ae650dSJack F Vogel 671031d839SEric Joyner static pci_vendor_info_t ixl_vendor_info_array[] = 6861ae650dSJack F Vogel { 691031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710, "Intel(R) Ethernet Controller X710 for 10GbE SFP+"), 701031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_B, "Intel(R) Ethernet Controller XL710 for 40GbE backplane"), 711031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_C, "Intel(R) Ethernet Controller X710 for 10GbE backplane"), 721031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_A, "Intel(R) Ethernet Controller XL710 for 40GbE QSFP+"), 731031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_B, "Intel(R) Ethernet Controller XL710 for 40GbE QSFP+"), 741031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_C, "Intel(R) Ethernet Controller X710 for 10GbE QSFP+"), 751031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T, "Intel(R) Ethernet Controller X710 for 10GBASE-T"), 761031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T4, "Intel(R) Ethernet Controller X710/X557-AT 10GBASE-T"), 771031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_KX_X722, "Intel(R) Ethernet Connection X722 for 10GbE backplane"), 781031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_QSFP_X722, "Intel(R) Ethernet Connection X722 for 10GbE QSFP+"), 791031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_X722, "Intel(R) Ethernet Connection X722 for 10GbE SFP+"), 801031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_1G_BASE_T_X722, "Intel(R) Ethernet Connection X722 for 1GbE"), 811031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_10G_BASE_T_X722, "Intel(R) Ethernet Connection X722 for 10GBASE-T"), 821031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_I_X722, "Intel(R) Ethernet Connection X722 for 10GbE SFP+"), 831031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_B, "Intel(R) Ethernet Controller XXV710 for 25GbE backplane"), 841031d839SEric Joyner PVIDV(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_25G_SFP28, "Intel(R) Ethernet Controller XXV710 for 25GbE SFP28"), 8561ae650dSJack F Vogel /* required last entry */ 861031d839SEric Joyner PVID_END 8761ae650dSJack F Vogel }; 8861ae650dSJack F Vogel 8961ae650dSJack F Vogel /********************************************************************* 9061ae650dSJack F Vogel * Function prototypes 9161ae650dSJack F Vogel *********************************************************************/ 921031d839SEric Joyner /*** IFLIB interface ***/ 931031d839SEric Joyner static void *ixl_register(device_t dev); 941031d839SEric Joyner static int ixl_if_attach_pre(if_ctx_t ctx); 951031d839SEric Joyner static int ixl_if_attach_post(if_ctx_t ctx); 961031d839SEric Joyner static int ixl_if_detach(if_ctx_t ctx); 971031d839SEric Joyner static int ixl_if_shutdown(if_ctx_t ctx); 981031d839SEric Joyner static int ixl_if_suspend(if_ctx_t ctx); 991031d839SEric Joyner static int ixl_if_resume(if_ctx_t ctx); 1001031d839SEric Joyner static int ixl_if_msix_intr_assign(if_ctx_t ctx, int msix); 1011031d839SEric Joyner static void ixl_if_enable_intr(if_ctx_t ctx); 1021031d839SEric Joyner static void ixl_if_disable_intr(if_ctx_t ctx); 1031031d839SEric Joyner static int ixl_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid); 1041031d839SEric Joyner static int ixl_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid); 1051031d839SEric Joyner static int ixl_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets); 1061031d839SEric Joyner static int ixl_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nqs, int nqsets); 1071031d839SEric Joyner static void ixl_if_queues_free(if_ctx_t ctx); 1081031d839SEric Joyner static void ixl_if_update_admin_status(if_ctx_t ctx); 1091031d839SEric Joyner static void ixl_if_multi_set(if_ctx_t ctx); 1101031d839SEric Joyner static int ixl_if_mtu_set(if_ctx_t ctx, uint32_t mtu); 1111031d839SEric Joyner static void ixl_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr); 1121031d839SEric Joyner static int ixl_if_media_change(if_ctx_t ctx); 1131031d839SEric Joyner static int ixl_if_promisc_set(if_ctx_t ctx, int flags); 1141031d839SEric Joyner static void ixl_if_timer(if_ctx_t ctx, uint16_t qid); 1151031d839SEric Joyner static void ixl_if_vlan_register(if_ctx_t ctx, u16 vtag); 1161031d839SEric Joyner static void ixl_if_vlan_unregister(if_ctx_t ctx, u16 vtag); 1171031d839SEric Joyner static uint64_t ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt); 1181031d839SEric Joyner static void ixl_if_vflr_handle(if_ctx_t ctx); 1191031d839SEric Joyner // static void ixl_if_link_intr_enable(if_ctx_t ctx); 1201031d839SEric Joyner static int ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req); 1211031d839SEric Joyner static int ixl_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data); 1226c426059SEric Joyner 1231031d839SEric Joyner /*** Other ***/ 1241031d839SEric Joyner static int ixl_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int); 1251031d839SEric Joyner static void ixl_save_pf_tunables(struct ixl_pf *); 1261031d839SEric Joyner static int ixl_allocate_pci_resources(struct ixl_pf *); 12761ae650dSJack F Vogel 12861ae650dSJack F Vogel /********************************************************************* 12961ae650dSJack F Vogel * FreeBSD Device Interface Entry Points 13061ae650dSJack F Vogel *********************************************************************/ 13161ae650dSJack F Vogel 13261ae650dSJack F Vogel static device_method_t ixl_methods[] = { 13361ae650dSJack F Vogel /* Device interface */ 1341031d839SEric Joyner DEVMETHOD(device_register, ixl_register), 1351031d839SEric Joyner DEVMETHOD(device_probe, iflib_device_probe), 1361031d839SEric Joyner DEVMETHOD(device_attach, iflib_device_attach), 1371031d839SEric Joyner DEVMETHOD(device_detach, iflib_device_detach), 1381031d839SEric Joyner DEVMETHOD(device_shutdown, iflib_device_shutdown), 13956c2c47bSJack F Vogel #ifdef PCI_IOV 140a48d00d2SEric Joyner DEVMETHOD(pci_iov_init, ixl_iov_init), 141a48d00d2SEric Joyner DEVMETHOD(pci_iov_uninit, ixl_iov_uninit), 142a48d00d2SEric Joyner DEVMETHOD(pci_iov_add_vf, ixl_add_vf), 14356c2c47bSJack F Vogel #endif 1441031d839SEric Joyner DEVMETHOD_END 14561ae650dSJack F Vogel }; 14661ae650dSJack F Vogel 14761ae650dSJack F Vogel static driver_t ixl_driver = { 14861ae650dSJack F Vogel "ixl", ixl_methods, sizeof(struct ixl_pf), 14961ae650dSJack F Vogel }; 15061ae650dSJack F Vogel 15161ae650dSJack F Vogel devclass_t ixl_devclass; 15261ae650dSJack F Vogel DRIVER_MODULE(ixl, pci, ixl_driver, ixl_devclass, 0, 0); 153*0dc34160SWarner Losh IFLIB_PNP_INFO(pci, ixl, ixl_vendor_info_array); 1541031d839SEric Joyner MODULE_VERSION(ixl, 3); 155cb6b8299SEric Joyner 15661ae650dSJack F Vogel MODULE_DEPEND(ixl, pci, 1, 1, 1); 15761ae650dSJack F Vogel MODULE_DEPEND(ixl, ether, 1, 1, 1); 1581031d839SEric Joyner MODULE_DEPEND(ixl, iflib, 1, 1, 1); 1591031d839SEric Joyner 1601031d839SEric Joyner static device_method_t ixl_if_methods[] = { 1611031d839SEric Joyner DEVMETHOD(ifdi_attach_pre, ixl_if_attach_pre), 1621031d839SEric Joyner DEVMETHOD(ifdi_attach_post, ixl_if_attach_post), 1631031d839SEric Joyner DEVMETHOD(ifdi_detach, ixl_if_detach), 1641031d839SEric Joyner DEVMETHOD(ifdi_shutdown, ixl_if_shutdown), 1651031d839SEric Joyner DEVMETHOD(ifdi_suspend, ixl_if_suspend), 1661031d839SEric Joyner DEVMETHOD(ifdi_resume, ixl_if_resume), 1671031d839SEric Joyner DEVMETHOD(ifdi_init, ixl_if_init), 1681031d839SEric Joyner DEVMETHOD(ifdi_stop, ixl_if_stop), 1691031d839SEric Joyner DEVMETHOD(ifdi_msix_intr_assign, ixl_if_msix_intr_assign), 1701031d839SEric Joyner DEVMETHOD(ifdi_intr_enable, ixl_if_enable_intr), 1711031d839SEric Joyner DEVMETHOD(ifdi_intr_disable, ixl_if_disable_intr), 1721031d839SEric Joyner //DEVMETHOD(ifdi_link_intr_enable, ixl_if_link_intr_enable), 1731031d839SEric Joyner DEVMETHOD(ifdi_rx_queue_intr_enable, ixl_if_rx_queue_intr_enable), 1741031d839SEric Joyner DEVMETHOD(ifdi_tx_queue_intr_enable, ixl_if_tx_queue_intr_enable), 1751031d839SEric Joyner DEVMETHOD(ifdi_tx_queues_alloc, ixl_if_tx_queues_alloc), 1761031d839SEric Joyner DEVMETHOD(ifdi_rx_queues_alloc, ixl_if_rx_queues_alloc), 1771031d839SEric Joyner DEVMETHOD(ifdi_queues_free, ixl_if_queues_free), 1781031d839SEric Joyner DEVMETHOD(ifdi_update_admin_status, ixl_if_update_admin_status), 1791031d839SEric Joyner DEVMETHOD(ifdi_multi_set, ixl_if_multi_set), 1801031d839SEric Joyner DEVMETHOD(ifdi_mtu_set, ixl_if_mtu_set), 1811031d839SEric Joyner DEVMETHOD(ifdi_media_status, ixl_if_media_status), 1821031d839SEric Joyner DEVMETHOD(ifdi_media_change, ixl_if_media_change), 1831031d839SEric Joyner DEVMETHOD(ifdi_promisc_set, ixl_if_promisc_set), 1841031d839SEric Joyner DEVMETHOD(ifdi_timer, ixl_if_timer), 1851031d839SEric Joyner DEVMETHOD(ifdi_vlan_register, ixl_if_vlan_register), 1861031d839SEric Joyner DEVMETHOD(ifdi_vlan_unregister, ixl_if_vlan_unregister), 1871031d839SEric Joyner DEVMETHOD(ifdi_get_counter, ixl_if_get_counter), 1881031d839SEric Joyner DEVMETHOD(ifdi_vflr_handle, ixl_if_vflr_handle), 1891031d839SEric Joyner DEVMETHOD(ifdi_i2c_req, ixl_if_i2c_req), 1901031d839SEric Joyner DEVMETHOD(ifdi_priv_ioctl, ixl_if_priv_ioctl), 1911031d839SEric Joyner // ifdi_led_func 1921031d839SEric Joyner // ifdi_debug 1931031d839SEric Joyner DEVMETHOD_END 1941031d839SEric Joyner }; 1951031d839SEric Joyner 1961031d839SEric Joyner static driver_t ixl_if_driver = { 1971031d839SEric Joyner "ixl_if", ixl_if_methods, sizeof(struct ixl_pf) 1981031d839SEric Joyner }; 19931830672SJack F Vogel 20061ae650dSJack F Vogel /* 20161ae650dSJack F Vogel ** TUNEABLE PARAMETERS: 20261ae650dSJack F Vogel */ 20361ae650dSJack F Vogel 20461ae650dSJack F Vogel static SYSCTL_NODE(_hw, OID_AUTO, ixl, CTLFLAG_RD, 0, 20561ae650dSJack F Vogel "IXL driver parameters"); 20661ae650dSJack F Vogel 20761ae650dSJack F Vogel /* 208ceebc2f3SEric Joyner * Leave this on unless you need to send flow control 209ceebc2f3SEric Joyner * frames (or other control frames) from software 210ceebc2f3SEric Joyner */ 2114294f337SSean Bruno static int ixl_enable_tx_fc_filter = 1; 2124294f337SSean Bruno TUNABLE_INT("hw.ixl.enable_tx_fc_filter", 2134294f337SSean Bruno &ixl_enable_tx_fc_filter); 2144294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, enable_tx_fc_filter, CTLFLAG_RDTUN, 2154294f337SSean Bruno &ixl_enable_tx_fc_filter, 0, 2164294f337SSean Bruno "Filter out packets with Ethertype 0x8808 from being sent out by non-HW sources"); 2174294f337SSean Bruno 2181031d839SEric Joyner static int ixl_i2c_access_method = 0; 2191031d839SEric Joyner TUNABLE_INT("hw.ixl.i2c_access_method", 2201031d839SEric Joyner &ixl_i2c_access_method); 2211031d839SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, i2c_access_method, CTLFLAG_RDTUN, 2221031d839SEric Joyner &ixl_i2c_access_method, 0, 2231031d839SEric Joyner IXL_SYSCTL_HELP_I2C_METHOD); 2241031d839SEric Joyner 225ceebc2f3SEric Joyner /* 226ceebc2f3SEric Joyner * Different method for processing TX descriptor 227ceebc2f3SEric Joyner * completion. 228ceebc2f3SEric Joyner */ 229ceebc2f3SEric Joyner static int ixl_enable_head_writeback = 1; 230ceebc2f3SEric Joyner TUNABLE_INT("hw.ixl.enable_head_writeback", 231ceebc2f3SEric Joyner &ixl_enable_head_writeback); 232ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, enable_head_writeback, CTLFLAG_RDTUN, 233ceebc2f3SEric Joyner &ixl_enable_head_writeback, 0, 234ceebc2f3SEric Joyner "For detecting last completed TX descriptor by hardware, use value written by HW instead of checking descriptors"); 235ceebc2f3SEric Joyner 2364294f337SSean Bruno static int ixl_core_debug_mask = 0; 2374294f337SSean Bruno TUNABLE_INT("hw.ixl.core_debug_mask", 2384294f337SSean Bruno &ixl_core_debug_mask); 2394294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, core_debug_mask, CTLFLAG_RDTUN, 2404294f337SSean Bruno &ixl_core_debug_mask, 0, 2414294f337SSean Bruno "Display debug statements that are printed in non-shared code"); 2424294f337SSean Bruno 2434294f337SSean Bruno static int ixl_shared_debug_mask = 0; 2444294f337SSean Bruno TUNABLE_INT("hw.ixl.shared_debug_mask", 2454294f337SSean Bruno &ixl_shared_debug_mask); 2464294f337SSean Bruno SYSCTL_INT(_hw_ixl, OID_AUTO, shared_debug_mask, CTLFLAG_RDTUN, 2474294f337SSean Bruno &ixl_shared_debug_mask, 0, 2484294f337SSean Bruno "Display debug statements that are printed in shared code"); 2494294f337SSean Bruno 2501031d839SEric Joyner #if 0 25161ae650dSJack F Vogel /* 25261ae650dSJack F Vogel ** Controls for Interrupt Throttling 25361ae650dSJack F Vogel ** - true/false for dynamic adjustment 25461ae650dSJack F Vogel ** - default values for static ITR 25561ae650dSJack F Vogel */ 2561031d839SEric Joyner static int ixl_dynamic_rx_itr = 0; 25761ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_rx_itr", &ixl_dynamic_rx_itr); 25861ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_rx_itr, CTLFLAG_RDTUN, 25961ae650dSJack F Vogel &ixl_dynamic_rx_itr, 0, "Dynamic RX Interrupt Rate"); 26061ae650dSJack F Vogel 2611031d839SEric Joyner static int ixl_dynamic_tx_itr = 0; 26261ae650dSJack F Vogel TUNABLE_INT("hw.ixl.dynamic_tx_itr", &ixl_dynamic_tx_itr); 26361ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, dynamic_tx_itr, CTLFLAG_RDTUN, 26461ae650dSJack F Vogel &ixl_dynamic_tx_itr, 0, "Dynamic TX Interrupt Rate"); 2651031d839SEric Joyner #endif 26661ae650dSJack F Vogel 2674294f337SSean Bruno static int ixl_rx_itr = IXL_ITR_8K; 26861ae650dSJack F Vogel TUNABLE_INT("hw.ixl.rx_itr", &ixl_rx_itr); 26961ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, rx_itr, CTLFLAG_RDTUN, 27061ae650dSJack F Vogel &ixl_rx_itr, 0, "RX Interrupt Rate"); 27161ae650dSJack F Vogel 2724294f337SSean Bruno static int ixl_tx_itr = IXL_ITR_4K; 27361ae650dSJack F Vogel TUNABLE_INT("hw.ixl.tx_itr", &ixl_tx_itr); 27461ae650dSJack F Vogel SYSCTL_INT(_hw_ixl, OID_AUTO, tx_itr, CTLFLAG_RDTUN, 27561ae650dSJack F Vogel &ixl_tx_itr, 0, "TX Interrupt Rate"); 27661ae650dSJack F Vogel 277cb6b8299SEric Joyner #ifdef IXL_IW 278cb6b8299SEric Joyner int ixl_enable_iwarp = 0; 279cb6b8299SEric Joyner TUNABLE_INT("hw.ixl.enable_iwarp", &ixl_enable_iwarp); 280ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, enable_iwarp, CTLFLAG_RDTUN, 281ceebc2f3SEric Joyner &ixl_enable_iwarp, 0, "iWARP enabled"); 282ceebc2f3SEric Joyner 283ceebc2f3SEric Joyner #if __FreeBSD_version < 1100000 284ceebc2f3SEric Joyner int ixl_limit_iwarp_msix = 1; 285ceebc2f3SEric Joyner #else 286ceebc2f3SEric Joyner int ixl_limit_iwarp_msix = IXL_IW_MAX_MSIX; 287ceebc2f3SEric Joyner #endif 288ceebc2f3SEric Joyner TUNABLE_INT("hw.ixl.limit_iwarp_msix", &ixl_limit_iwarp_msix); 289ceebc2f3SEric Joyner SYSCTL_INT(_hw_ixl, OID_AUTO, limit_iwarp_msix, CTLFLAG_RDTUN, 290ceebc2f3SEric Joyner &ixl_limit_iwarp_msix, 0, "Limit MSIX vectors assigned to iWARP"); 291cb6b8299SEric Joyner #endif 292cb6b8299SEric Joyner 2931031d839SEric Joyner extern struct if_txrx ixl_txrx_hwb; 2941031d839SEric Joyner extern struct if_txrx ixl_txrx_dwb; 295e5100ee2SJack F Vogel 2961031d839SEric Joyner static struct if_shared_ctx ixl_sctx_init = { 2971031d839SEric Joyner .isc_magic = IFLIB_MAGIC, 2981031d839SEric Joyner .isc_q_align = PAGE_SIZE, 2997f87c040SMarius Strobl .isc_tx_maxsize = IXL_TSO_SIZE + sizeof(struct ether_vlan_header), 3001031d839SEric Joyner .isc_tx_maxsegsize = IXL_MAX_DMA_SEG_SIZE, 3017f87c040SMarius Strobl .isc_tso_maxsize = IXL_TSO_SIZE + sizeof(struct ether_vlan_header), 3027f87c040SMarius Strobl .isc_tso_maxsegsize = IXL_MAX_DMA_SEG_SIZE, 3031031d839SEric Joyner .isc_rx_maxsize = 16384, 3041031d839SEric Joyner .isc_rx_nsegments = IXL_MAX_RX_SEGS, 3051031d839SEric Joyner .isc_rx_maxsegsize = IXL_MAX_DMA_SEG_SIZE, 3061031d839SEric Joyner .isc_nfl = 1, 3071031d839SEric Joyner .isc_ntxqs = 1, 3081031d839SEric Joyner .isc_nrxqs = 1, 3091031d839SEric Joyner 3101031d839SEric Joyner .isc_admin_intrcnt = 1, 3111031d839SEric Joyner .isc_vendor_info = ixl_vendor_info_array, 3121031d839SEric Joyner .isc_driver_version = IXL_DRIVER_VERSION_STRING, 3131031d839SEric Joyner .isc_driver = &ixl_if_driver, 3141031d839SEric Joyner .isc_flags = IFLIB_NEED_SCRATCH | IFLIB_NEED_ZERO_CSUM | IFLIB_ADMIN_ALWAYS_RUN, 3151031d839SEric Joyner 3161031d839SEric Joyner .isc_nrxd_min = {IXL_MIN_RING}, 3171031d839SEric Joyner .isc_ntxd_min = {IXL_MIN_RING}, 3181031d839SEric Joyner .isc_nrxd_max = {IXL_MAX_RING}, 3191031d839SEric Joyner .isc_ntxd_max = {IXL_MAX_RING}, 3201031d839SEric Joyner .isc_nrxd_default = {IXL_DEFAULT_RING}, 3211031d839SEric Joyner .isc_ntxd_default = {IXL_DEFAULT_RING}, 3221031d839SEric Joyner }; 3231031d839SEric Joyner 3241031d839SEric Joyner if_shared_ctx_t ixl_sctx = &ixl_sctx_init; 3251031d839SEric Joyner 3261031d839SEric Joyner /*** Functions ***/ 3271031d839SEric Joyner static void * 3281031d839SEric Joyner ixl_register(device_t dev) 3291031d839SEric Joyner { 3301031d839SEric Joyner return (ixl_sctx); 3311031d839SEric Joyner } 33261ae650dSJack F Vogel 33361ae650dSJack F Vogel static int 3341031d839SEric Joyner ixl_allocate_pci_resources(struct ixl_pf *pf) 33561ae650dSJack F Vogel { 3361031d839SEric Joyner int rid; 3371031d839SEric Joyner struct i40e_hw *hw = &pf->hw; 3381031d839SEric Joyner device_t dev = iflib_get_dev(pf->vsi.ctx); 33961ae650dSJack F Vogel 3401031d839SEric Joyner /* Map BAR0 */ 3411031d839SEric Joyner rid = PCIR_BAR(0); 3421031d839SEric Joyner pf->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 3431031d839SEric Joyner &rid, RF_ACTIVE); 34461ae650dSJack F Vogel 3451031d839SEric Joyner if (!(pf->pci_mem)) { 3461031d839SEric Joyner device_printf(dev, "Unable to allocate bus resource: PCI memory\n"); 34761ae650dSJack F Vogel return (ENXIO); 34861ae650dSJack F Vogel } 34961ae650dSJack F Vogel 3501031d839SEric Joyner /* Save off the PCI information */ 3511031d839SEric Joyner hw->vendor_id = pci_get_vendor(dev); 3521031d839SEric Joyner hw->device_id = pci_get_device(dev); 3531031d839SEric Joyner hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); 3541031d839SEric Joyner hw->subsystem_vendor_id = 3551031d839SEric Joyner pci_read_config(dev, PCIR_SUBVEND_0, 2); 3561031d839SEric Joyner hw->subsystem_device_id = 3571031d839SEric Joyner pci_read_config(dev, PCIR_SUBDEV_0, 2); 3584294f337SSean Bruno 3591031d839SEric Joyner hw->bus.device = pci_get_slot(dev); 3601031d839SEric Joyner hw->bus.func = pci_get_function(dev); 3614294f337SSean Bruno 3621031d839SEric Joyner /* Save off register access information */ 3631031d839SEric Joyner pf->osdep.mem_bus_space_tag = 3641031d839SEric Joyner rman_get_bustag(pf->pci_mem); 3651031d839SEric Joyner pf->osdep.mem_bus_space_handle = 3661031d839SEric Joyner rman_get_bushandle(pf->pci_mem); 3671031d839SEric Joyner pf->osdep.mem_bus_space_size = rman_get_size(pf->pci_mem); 3681031d839SEric Joyner pf->osdep.flush_reg = I40E_GLGEN_STAT; 3691031d839SEric Joyner pf->osdep.dev = dev; 370cb6b8299SEric Joyner 3711031d839SEric Joyner pf->hw.hw_addr = (u8 *) &pf->osdep.mem_bus_space_handle; 3721031d839SEric Joyner pf->hw.back = &pf->osdep; 3734294f337SSean Bruno 3744294f337SSean Bruno return (0); 3754294f337SSean Bruno } 3764294f337SSean Bruno 37761ae650dSJack F Vogel static int 3781031d839SEric Joyner ixl_if_attach_pre(if_ctx_t ctx) 37961ae650dSJack F Vogel { 3801031d839SEric Joyner device_t dev; 38161ae650dSJack F Vogel struct ixl_pf *pf; 38261ae650dSJack F Vogel struct i40e_hw *hw; 38361ae650dSJack F Vogel struct ixl_vsi *vsi; 3841031d839SEric Joyner if_softc_ctx_t scctx; 3851031d839SEric Joyner struct i40e_filter_control_settings filter; 3864294f337SSean Bruno enum i40e_status_code status; 38761ae650dSJack F Vogel int error = 0; 38861ae650dSJack F Vogel 3891031d839SEric Joyner INIT_DEBUGOUT("ixl_if_attach_pre: begin"); 39061ae650dSJack F Vogel 39161ae650dSJack F Vogel /* Allocate, clear, and link in our primary soft structure */ 3921031d839SEric Joyner dev = iflib_get_dev(ctx); 3931031d839SEric Joyner pf = iflib_get_softc(ctx); 3941031d839SEric Joyner vsi = &pf->vsi; 3951031d839SEric Joyner vsi->back = pf; 3961031d839SEric Joyner pf->dev = dev; 39761ae650dSJack F Vogel hw = &pf->hw; 39861ae650dSJack F Vogel 39961ae650dSJack F Vogel /* 40061ae650dSJack F Vogel ** Note this assumes we have a single embedded VSI, 40161ae650dSJack F Vogel ** this could be enhanced later to allocate multiple 40261ae650dSJack F Vogel */ 4031031d839SEric Joyner //vsi->dev = pf->dev; 4041031d839SEric Joyner vsi->hw = &pf->hw; 4051031d839SEric Joyner vsi->id = 0; 4061031d839SEric Joyner vsi->num_vlans = 0; 4071031d839SEric Joyner vsi->ctx = ctx; 4081031d839SEric Joyner vsi->media = iflib_get_media(ctx); 4091031d839SEric Joyner vsi->shared = scctx = iflib_get_softc_ctx(ctx); 41061ae650dSJack F Vogel 4114294f337SSean Bruno /* Save tunable values */ 4121031d839SEric Joyner ixl_save_pf_tunables(pf); 41361ae650dSJack F Vogel 41461ae650dSJack F Vogel /* Do PCI setup - map BAR0, etc */ 41561ae650dSJack F Vogel if (ixl_allocate_pci_resources(pf)) { 41661ae650dSJack F Vogel device_printf(dev, "Allocation of PCI resources failed\n"); 41761ae650dSJack F Vogel error = ENXIO; 4181031d839SEric Joyner goto err_pci_res; 41961ae650dSJack F Vogel } 42061ae650dSJack F Vogel 42161ae650dSJack F Vogel /* Establish a clean starting point */ 42261ae650dSJack F Vogel i40e_clear_hw(hw); 4234294f337SSean Bruno status = i40e_pf_reset(hw); 4244294f337SSean Bruno if (status) { 4254294f337SSean Bruno device_printf(dev, "PF reset failure %s\n", 4264294f337SSean Bruno i40e_stat_str(hw, status)); 42761ae650dSJack F Vogel error = EIO; 42861ae650dSJack F Vogel goto err_out; 42961ae650dSJack F Vogel } 43061ae650dSJack F Vogel 43161ae650dSJack F Vogel /* Initialize the shared code */ 4324294f337SSean Bruno status = i40e_init_shared_code(hw); 4334294f337SSean Bruno if (status) { 4344294f337SSean Bruno device_printf(dev, "Unable to initialize shared code, error %s\n", 4354294f337SSean Bruno i40e_stat_str(hw, status)); 43661ae650dSJack F Vogel error = EIO; 43761ae650dSJack F Vogel goto err_out; 43861ae650dSJack F Vogel } 43961ae650dSJack F Vogel 44061ae650dSJack F Vogel /* Set up the admin queue */ 4414294f337SSean Bruno hw->aq.num_arq_entries = IXL_AQ_LEN; 4424294f337SSean Bruno hw->aq.num_asq_entries = IXL_AQ_LEN; 4434294f337SSean Bruno hw->aq.arq_buf_size = IXL_AQ_BUF_SZ; 4444294f337SSean Bruno hw->aq.asq_buf_size = IXL_AQ_BUF_SZ; 4454294f337SSean Bruno 4464294f337SSean Bruno status = i40e_init_adminq(hw); 4474294f337SSean Bruno if (status != 0 && status != I40E_ERR_FIRMWARE_API_VERSION) { 4484294f337SSean Bruno device_printf(dev, "Unable to initialize Admin Queue, error %s\n", 4494294f337SSean Bruno i40e_stat_str(hw, status)); 450fdb6f38aSEric Joyner error = EIO; 451fdb6f38aSEric Joyner goto err_out; 452fdb6f38aSEric Joyner } 4531d767a8eSEric Joyner ixl_print_nvm_version(pf); 4541d767a8eSEric Joyner 4554294f337SSean Bruno if (status == I40E_ERR_FIRMWARE_API_VERSION) { 45661ae650dSJack F Vogel device_printf(dev, "The driver for the device stopped " 457ceebc2f3SEric Joyner "because the NVM image is newer than expected.\n"); 458ceebc2f3SEric Joyner device_printf(dev, "You must install the most recent version of " 45961ae650dSJack F Vogel "the network driver.\n"); 460fdb6f38aSEric Joyner error = EIO; 46161ae650dSJack F Vogel goto err_out; 46261ae650dSJack F Vogel } 46361ae650dSJack F Vogel 46461ae650dSJack F Vogel if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR && 465ceebc2f3SEric Joyner hw->aq.api_min_ver > I40E_FW_MINOR_VERSION(hw)) { 46661ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 467ceebc2f3SEric Joyner "a newer version of the NVM image than expected.\n"); 468ceebc2f3SEric Joyner device_printf(dev, "Please install the most recent version " 469ceebc2f3SEric Joyner "of the network driver.\n"); 470ceebc2f3SEric Joyner } else if (hw->aq.api_maj_ver == 1 && hw->aq.api_min_ver < 4) { 47161ae650dSJack F Vogel device_printf(dev, "The driver for the device detected " 472ceebc2f3SEric Joyner "an older version of the NVM image than expected.\n"); 473ceebc2f3SEric Joyner device_printf(dev, "Please update the NVM image.\n"); 474ceebc2f3SEric Joyner } 47561ae650dSJack F Vogel 47661ae650dSJack F Vogel /* Clear PXE mode */ 47761ae650dSJack F Vogel i40e_clear_pxe_mode(hw); 47861ae650dSJack F Vogel 47961ae650dSJack F Vogel /* Get capabilities from the device */ 48061ae650dSJack F Vogel error = ixl_get_hw_capabilities(pf); 48161ae650dSJack F Vogel if (error) { 4821031d839SEric Joyner device_printf(dev, "get_hw_capabilities failed: %d\n", 4831031d839SEric Joyner error); 48461ae650dSJack F Vogel goto err_get_cap; 48561ae650dSJack F Vogel } 48661ae650dSJack F Vogel 48761ae650dSJack F Vogel /* Set up host memory cache */ 4884294f337SSean Bruno status = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, 48956c2c47bSJack F Vogel hw->func_caps.num_rx_qp, 0, 0); 4904294f337SSean Bruno if (status) { 4914294f337SSean Bruno device_printf(dev, "init_lan_hmc failed: %s\n", 4924294f337SSean Bruno i40e_stat_str(hw, status)); 49361ae650dSJack F Vogel goto err_get_cap; 49461ae650dSJack F Vogel } 4954294f337SSean Bruno status = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); 4964294f337SSean Bruno if (status) { 4974294f337SSean Bruno device_printf(dev, "configure_lan_hmc failed: %s\n", 4984294f337SSean Bruno i40e_stat_str(hw, status)); 49961ae650dSJack F Vogel goto err_mac_hmc; 50061ae650dSJack F Vogel } 50161ae650dSJack F Vogel 502d4683565SEric Joyner /* Disable LLDP from the firmware for certain NVM versions */ 503d4683565SEric Joyner if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) || 504ceebc2f3SEric Joyner (pf->hw.aq.fw_maj_ver < 4)) { 50561ae650dSJack F Vogel i40e_aq_stop_lldp(hw, TRUE, NULL); 506ceebc2f3SEric Joyner pf->state |= IXL_PF_STATE_FW_LLDP_DISABLED; 507ceebc2f3SEric Joyner } 50861ae650dSJack F Vogel 5094294f337SSean Bruno /* Get MAC addresses from hardware */ 51061ae650dSJack F Vogel i40e_get_mac_addr(hw, hw->mac.addr); 51161ae650dSJack F Vogel error = i40e_validate_mac_addr(hw->mac.addr); 51261ae650dSJack F Vogel if (error) { 51361ae650dSJack F Vogel device_printf(dev, "validate_mac_addr failed: %d\n", error); 51461ae650dSJack F Vogel goto err_mac_hmc; 51561ae650dSJack F Vogel } 51661ae650dSJack F Vogel bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN); 5171031d839SEric Joyner iflib_set_mac(ctx, hw->mac.addr); 51861ae650dSJack F Vogel i40e_get_port_mac_addr(hw, hw->mac.port_addr); 51961ae650dSJack F Vogel 5201031d839SEric Joyner /* Set up the device filtering */ 5211031d839SEric Joyner bzero(&filter, sizeof(filter)); 5221031d839SEric Joyner filter.enable_ethtype = TRUE; 5231031d839SEric Joyner filter.enable_macvlan = TRUE; 5241031d839SEric Joyner filter.enable_fdir = FALSE; 5251031d839SEric Joyner filter.hash_lut_size = I40E_HASH_LUT_SIZE_512; 5261031d839SEric Joyner if (i40e_set_filter_control(hw, &filter)) 5271031d839SEric Joyner device_printf(dev, "i40e_set_filter_control() failed\n"); 5281031d839SEric Joyner 529ceebc2f3SEric Joyner /* Query device FW LLDP status */ 530ceebc2f3SEric Joyner ixl_get_fw_lldp_status(pf); 531ceebc2f3SEric Joyner /* Tell FW to apply DCB config on link up */ 532ceebc2f3SEric Joyner i40e_aq_set_dcb_parameters(hw, true, NULL); 533ceebc2f3SEric Joyner 5341031d839SEric Joyner /* Fill out iflib parameters */ 5351031d839SEric Joyner if (hw->mac.type == I40E_MAC_X722) 5361031d839SEric Joyner scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 128; 5371031d839SEric Joyner else 5381031d839SEric Joyner scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 64; 5391031d839SEric Joyner if (vsi->enable_head_writeback) { 5401031d839SEric Joyner scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] 5411031d839SEric Joyner * sizeof(struct i40e_tx_desc) + sizeof(u32), DBA_ALIGN); 5421031d839SEric Joyner scctx->isc_txrx = &ixl_txrx_hwb; 5431031d839SEric Joyner } else { 5441031d839SEric Joyner scctx->isc_txqsizes[0] = roundup2(scctx->isc_ntxd[0] 5451031d839SEric Joyner * sizeof(struct i40e_tx_desc), DBA_ALIGN); 5461031d839SEric Joyner scctx->isc_txrx = &ixl_txrx_dwb; 5471031d839SEric Joyner } 5481031d839SEric Joyner scctx->isc_rxqsizes[0] = roundup2(scctx->isc_nrxd[0] 5491031d839SEric Joyner * sizeof(union i40e_32byte_rx_desc), DBA_ALIGN); 5501031d839SEric Joyner scctx->isc_msix_bar = PCIR_BAR(IXL_MSIX_BAR); 5511031d839SEric Joyner scctx->isc_tx_nsegments = IXL_MAX_TX_SEGS; 5521031d839SEric Joyner scctx->isc_tx_tso_segments_max = IXL_MAX_TSO_SEGS; 5531031d839SEric Joyner scctx->isc_tx_tso_size_max = IXL_TSO_SIZE; 5541031d839SEric Joyner scctx->isc_tx_tso_segsize_max = IXL_MAX_DMA_SEG_SIZE; 5551031d839SEric Joyner scctx->isc_rss_table_size = pf->hw.func_caps.rss_table_size; 5561031d839SEric Joyner scctx->isc_tx_csum_flags = CSUM_OFFLOAD; 5577f87c040SMarius Strobl scctx->isc_capabilities = scctx->isc_capenable = IXL_CAPS; 5584294f337SSean Bruno 5591031d839SEric Joyner INIT_DEBUGOUT("ixl_if_attach_pre: end"); 5601031d839SEric Joyner return (0); 5611031d839SEric Joyner 5621031d839SEric Joyner err_mac_hmc: 5631031d839SEric Joyner i40e_shutdown_lan_hmc(hw); 5641031d839SEric Joyner err_get_cap: 5651031d839SEric Joyner i40e_shutdown_adminq(hw); 5661031d839SEric Joyner err_out: 5671031d839SEric Joyner ixl_free_pci_resources(pf); 5681031d839SEric Joyner err_pci_res: 5691031d839SEric Joyner return (error); 57061ae650dSJack F Vogel } 57161ae650dSJack F Vogel 5721031d839SEric Joyner static int 5731031d839SEric Joyner ixl_if_attach_post(if_ctx_t ctx) 5741031d839SEric Joyner { 5751031d839SEric Joyner device_t dev; 5761031d839SEric Joyner struct ixl_pf *pf; 5771031d839SEric Joyner struct i40e_hw *hw; 5781031d839SEric Joyner struct ixl_vsi *vsi; 5791031d839SEric Joyner int error = 0; 5801031d839SEric Joyner enum i40e_status_code status; 5811031d839SEric Joyner 5821031d839SEric Joyner INIT_DEBUGOUT("ixl_if_attach_post: begin"); 5831031d839SEric Joyner 5841031d839SEric Joyner dev = iflib_get_dev(ctx); 5851031d839SEric Joyner pf = iflib_get_softc(ctx); 5861031d839SEric Joyner vsi = &pf->vsi; 5871031d839SEric Joyner vsi->ifp = iflib_get_ifp(ctx); 5881031d839SEric Joyner hw = &pf->hw; 5891031d839SEric Joyner 5904294f337SSean Bruno /* Setup OS network interface / ifnet */ 5911031d839SEric Joyner if (ixl_setup_interface(dev, pf)) { 5924294f337SSean Bruno device_printf(dev, "interface setup failed!\n"); 5934294f337SSean Bruno error = EIO; 5941031d839SEric Joyner goto err; 595223d846dSEric Joyner } 59661ae650dSJack F Vogel 59761ae650dSJack F Vogel /* Determine link state */ 5984294f337SSean Bruno if (ixl_attach_get_link_status(pf)) { 5994294f337SSean Bruno error = EINVAL; 6001031d839SEric Joyner goto err; 601e5100ee2SJack F Vogel } 60261ae650dSJack F Vogel 603b6c8f260SJack F Vogel error = ixl_switch_config(pf); 604b6c8f260SJack F Vogel if (error) { 6056c426059SEric Joyner device_printf(dev, "Initial ixl_switch_config() failed: %d\n", 6066c426059SEric Joyner error); 6071031d839SEric Joyner goto err; 608b6c8f260SJack F Vogel } 609b6c8f260SJack F Vogel 6101031d839SEric Joyner /* Add protocol filters to list */ 6111031d839SEric Joyner ixl_init_filters(vsi); 6121031d839SEric Joyner 6131031d839SEric Joyner /* Init queue allocation manager */ 6141031d839SEric Joyner error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_tx_qp); 6151031d839SEric Joyner if (error) { 6161031d839SEric Joyner device_printf(dev, "Failed to init queue manager for PF queues, error %d\n", 6171031d839SEric Joyner error); 6181031d839SEric Joyner goto err; 6191031d839SEric Joyner } 6201031d839SEric Joyner /* reserve a contiguous allocation for the PF's VSI */ 6211031d839SEric Joyner error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, 6221031d839SEric Joyner max(vsi->num_rx_queues, vsi->num_tx_queues), &pf->qtag); 6231031d839SEric Joyner if (error) { 6241031d839SEric Joyner device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n", 6251031d839SEric Joyner error); 6261031d839SEric Joyner goto err; 6271031d839SEric Joyner } 6281031d839SEric Joyner device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n", 6291031d839SEric Joyner pf->qtag.num_allocated, pf->qtag.num_active); 6301031d839SEric Joyner 631223d846dSEric Joyner /* Limit PHY interrupts to link, autoneg, and modules failure */ 6324294f337SSean Bruno status = i40e_aq_set_phy_int_mask(hw, IXL_DEFAULT_PHY_INT_MASK, 633223d846dSEric Joyner NULL); 6344294f337SSean Bruno if (status) { 6354294f337SSean Bruno device_printf(dev, "i40e_aq_set_phy_mask() failed: err %s," 6364294f337SSean Bruno " aq_err %s\n", i40e_stat_str(hw, status), 6374294f337SSean Bruno i40e_aq_str(hw, hw->aq.asq_last_status)); 6381031d839SEric Joyner goto err; 639223d846dSEric Joyner } 640b6c8f260SJack F Vogel 6411031d839SEric Joyner /* Get the bus configuration and set the shared code */ 642cb6b8299SEric Joyner ixl_get_bus_info(pf); 64361ae650dSJack F Vogel 6441031d839SEric Joyner /* Keep admin queue interrupts active while driver is loaded */ 6451031d839SEric Joyner if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { 6466c426059SEric Joyner ixl_configure_intr0_msix(pf); 647cb6b8299SEric Joyner ixl_enable_intr0(hw); 648cb6b8299SEric Joyner } 649cb6b8299SEric Joyner 650cb6b8299SEric Joyner /* Set initial advertised speed sysctl value */ 651ceebc2f3SEric Joyner ixl_set_initial_advertised_speeds(pf); 652cb6b8299SEric Joyner 653fdb6f38aSEric Joyner /* Initialize statistics & add sysctls */ 654fdb6f38aSEric Joyner ixl_add_device_sysctls(pf); 65561ae650dSJack F Vogel ixl_pf_reset_stats(pf); 65661ae650dSJack F Vogel ixl_update_stats_counters(pf); 65761ae650dSJack F Vogel ixl_add_hw_stats(pf); 65861ae650dSJack F Vogel 6591031d839SEric Joyner hw->phy.get_link_info = true; 6601031d839SEric Joyner i40e_get_link_status(hw, &pf->link_up); 6611031d839SEric Joyner ixl_update_link_status(pf); 66261ae650dSJack F Vogel 66356c2c47bSJack F Vogel #ifdef PCI_IOV 6644294f337SSean Bruno ixl_initialize_sriov(pf); 66556c2c47bSJack F Vogel #endif 66656c2c47bSJack F Vogel 667cb6b8299SEric Joyner #ifdef IXL_IW 668cb6b8299SEric Joyner if (hw->func_caps.iwarp && ixl_enable_iwarp) { 669cb6b8299SEric Joyner pf->iw_enabled = (pf->iw_msix > 0) ? true : false; 670cb6b8299SEric Joyner if (pf->iw_enabled) { 671cb6b8299SEric Joyner error = ixl_iw_pf_attach(pf); 672cb6b8299SEric Joyner if (error) { 673cb6b8299SEric Joyner device_printf(dev, 674cb6b8299SEric Joyner "interfacing to iwarp driver failed: %d\n", 675cb6b8299SEric Joyner error); 6761031d839SEric Joyner goto err; 677ceebc2f3SEric Joyner } else 678ceebc2f3SEric Joyner device_printf(dev, "iWARP ready\n"); 679cb6b8299SEric Joyner } else 680cb6b8299SEric Joyner device_printf(dev, 681cb6b8299SEric Joyner "iwarp disabled on this device (no msix vectors)\n"); 682cb6b8299SEric Joyner } else { 683cb6b8299SEric Joyner pf->iw_enabled = false; 684cb6b8299SEric Joyner device_printf(dev, "The device is not iWARP enabled\n"); 685cb6b8299SEric Joyner } 686cb6b8299SEric Joyner #endif 687cb6b8299SEric Joyner 6881031d839SEric Joyner INIT_DBG_DEV(dev, "end"); 68961ae650dSJack F Vogel return (0); 69061ae650dSJack F Vogel 6911031d839SEric Joyner err: 6921031d839SEric Joyner INIT_DEBUGOUT("end: error %d", error); 6931031d839SEric Joyner /* ixl_if_detach() is called on error from this */ 69461ae650dSJack F Vogel return (error); 69561ae650dSJack F Vogel } 69661ae650dSJack F Vogel 69761ae650dSJack F Vogel static int 6981031d839SEric Joyner ixl_if_detach(if_ctx_t ctx) 69961ae650dSJack F Vogel { 7001031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 70161ae650dSJack F Vogel struct ixl_vsi *vsi = &pf->vsi; 7021031d839SEric Joyner struct i40e_hw *hw = &pf->hw; 7031031d839SEric Joyner device_t dev = pf->dev; 7046c426059SEric Joyner enum i40e_status_code status; 705cb6b8299SEric Joyner #if defined(PCI_IOV) || defined(IXL_IW) 70656c2c47bSJack F Vogel int error; 70756c2c47bSJack F Vogel #endif 70861ae650dSJack F Vogel 7091031d839SEric Joyner INIT_DBG_DEV(dev, "begin"); 710cb6b8299SEric Joyner 711cb6b8299SEric Joyner #ifdef IXL_IW 712cb6b8299SEric Joyner if (ixl_enable_iwarp && pf->iw_enabled) { 713cb6b8299SEric Joyner error = ixl_iw_pf_detach(pf); 714cb6b8299SEric Joyner if (error == EBUSY) { 715cb6b8299SEric Joyner device_printf(dev, "iwarp in use; stop it first.\n"); 716cb6b8299SEric Joyner return (error); 717cb6b8299SEric Joyner } 718cb6b8299SEric Joyner } 719cb6b8299SEric Joyner #endif 7201031d839SEric Joyner #ifdef PCI_IOV 7211031d839SEric Joyner error = pci_iov_detach(dev); 7221031d839SEric Joyner if (error != 0) { 7231031d839SEric Joyner device_printf(dev, "SR-IOV in use; detach first.\n"); 7241031d839SEric Joyner return (error); 7251031d839SEric Joyner } 7261031d839SEric Joyner #endif 7271031d839SEric Joyner /* Remove all previously allocated media types */ 7281031d839SEric Joyner ifmedia_removeall(vsi->media); 729cb6b8299SEric Joyner 7301031d839SEric Joyner /* Shutdown LAN HMC */ 7311031d839SEric Joyner if (hw->hmc.hmc_obj) { 7321031d839SEric Joyner status = i40e_shutdown_lan_hmc(hw); 7331031d839SEric Joyner if (status) 7341031d839SEric Joyner device_printf(dev, 7351031d839SEric Joyner "i40e_shutdown_lan_hmc() failed with status %s\n", 7361031d839SEric Joyner i40e_stat_str(hw, status)); 7371031d839SEric Joyner } 7381031d839SEric Joyner 7391031d839SEric Joyner /* Shutdown admin queue */ 7401031d839SEric Joyner ixl_disable_intr0(hw); 7411031d839SEric Joyner status = i40e_shutdown_adminq(hw); 7421031d839SEric Joyner if (status) 7431031d839SEric Joyner device_printf(dev, 7441031d839SEric Joyner "i40e_shutdown_adminq() failed with status %s\n", 7451031d839SEric Joyner i40e_stat_str(hw, status)); 7461031d839SEric Joyner 7474294f337SSean Bruno ixl_pf_qmgr_destroy(&pf->qmgr); 74861ae650dSJack F Vogel ixl_free_pci_resources(pf); 7491031d839SEric Joyner ixl_free_mac_filters(vsi); 7501031d839SEric Joyner INIT_DBG_DEV(dev, "end"); 75161ae650dSJack F Vogel return (0); 75261ae650dSJack F Vogel } 75361ae650dSJack F Vogel 7541031d839SEric Joyner /* TODO: Do shutdown-specific stuff here */ 7551031d839SEric Joyner static int 7561031d839SEric Joyner ixl_if_shutdown(if_ctx_t ctx) 7571031d839SEric Joyner { 7581031d839SEric Joyner int error = 0; 7591031d839SEric Joyner 7601031d839SEric Joyner INIT_DEBUGOUT("ixl_if_shutdown: begin"); 7611031d839SEric Joyner 7621031d839SEric Joyner /* TODO: Call ixl_if_stop()? */ 7631031d839SEric Joyner 7641031d839SEric Joyner /* TODO: Then setup low power mode */ 7651031d839SEric Joyner 7661031d839SEric Joyner return (error); 7671031d839SEric Joyner } 76861ae650dSJack F Vogel 76961ae650dSJack F Vogel static int 7701031d839SEric Joyner ixl_if_suspend(if_ctx_t ctx) 77161ae650dSJack F Vogel { 7721031d839SEric Joyner int error = 0; 7731031d839SEric Joyner 7741031d839SEric Joyner INIT_DEBUGOUT("ixl_if_suspend: begin"); 7751031d839SEric Joyner 7761031d839SEric Joyner /* TODO: Call ixl_if_stop()? */ 7771031d839SEric Joyner 7781031d839SEric Joyner /* TODO: Then setup low power mode */ 7791031d839SEric Joyner 7801031d839SEric Joyner return (error); 7811031d839SEric Joyner } 7821031d839SEric Joyner 7831031d839SEric Joyner static int 7841031d839SEric Joyner ixl_if_resume(if_ctx_t ctx) 7851031d839SEric Joyner { 7861031d839SEric Joyner struct ifnet *ifp = iflib_get_ifp(ctx); 7871031d839SEric Joyner 7881031d839SEric Joyner INIT_DEBUGOUT("ixl_if_resume: begin"); 7891031d839SEric Joyner 7901031d839SEric Joyner /* Read & clear wake-up registers */ 7911031d839SEric Joyner 7921031d839SEric Joyner /* Required after D3->D0 transition */ 7931031d839SEric Joyner if (ifp->if_flags & IFF_UP) 7941031d839SEric Joyner ixl_if_init(ctx); 7951031d839SEric Joyner 79661ae650dSJack F Vogel return (0); 79761ae650dSJack F Vogel } 79861ae650dSJack F Vogel 7991031d839SEric Joyner /* Set Report Status queue fields to 0 */ 8001031d839SEric Joyner static void 8011031d839SEric Joyner ixl_init_tx_rsqs(struct ixl_vsi *vsi) 8021031d839SEric Joyner { 8031031d839SEric Joyner if_softc_ctx_t scctx = vsi->shared; 8041031d839SEric Joyner struct ixl_tx_queue *tx_que; 8051031d839SEric Joyner int i, j; 8061031d839SEric Joyner 8071031d839SEric Joyner for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) { 8081031d839SEric Joyner struct tx_ring *txr = &tx_que->txr; 8091031d839SEric Joyner 8101031d839SEric Joyner txr->tx_rs_cidx = txr->tx_rs_pidx = txr->tx_cidx_processed = 0; 8111031d839SEric Joyner 8121031d839SEric Joyner for (j = 0; j < scctx->isc_ntxd[0]; j++) 8131031d839SEric Joyner txr->tx_rsq[j] = QIDX_INVALID; 8141031d839SEric Joyner } 8151031d839SEric Joyner } 8161031d839SEric Joyner 8171031d839SEric Joyner static void 8181031d839SEric Joyner ixl_init_tx_cidx(struct ixl_vsi *vsi) 8191031d839SEric Joyner { 8201031d839SEric Joyner struct ixl_tx_queue *tx_que; 8211031d839SEric Joyner int i; 8221031d839SEric Joyner 8231031d839SEric Joyner for (i = 0, tx_que = vsi->tx_queues; i < vsi->num_tx_queues; i++, tx_que++) { 8241031d839SEric Joyner struct tx_ring *txr = &tx_que->txr; 8251031d839SEric Joyner 8261031d839SEric Joyner txr->tx_cidx_processed = 0; 8271031d839SEric Joyner } 8281031d839SEric Joyner } 8291031d839SEric Joyner 8301031d839SEric Joyner void 8311031d839SEric Joyner ixl_if_init(if_ctx_t ctx) 8321031d839SEric Joyner { 8331031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 8341031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 8351031d839SEric Joyner struct i40e_hw *hw = &pf->hw; 8361031d839SEric Joyner device_t dev = iflib_get_dev(ctx); 8371031d839SEric Joyner u8 tmpaddr[ETHER_ADDR_LEN]; 8381031d839SEric Joyner int ret; 8391031d839SEric Joyner 8401031d839SEric Joyner /* 8411031d839SEric Joyner * If the aq is dead here, it probably means something outside of the driver 8421031d839SEric Joyner * did something to the adapter, like a PF reset. 8431031d839SEric Joyner * So rebuild the driver's state here if that occurs. 8441031d839SEric Joyner */ 8451031d839SEric Joyner if (!i40e_check_asq_alive(&pf->hw)) { 8461031d839SEric Joyner device_printf(dev, "Admin Queue is down; resetting...\n"); 8471031d839SEric Joyner ixl_teardown_hw_structs(pf); 8481031d839SEric Joyner ixl_reset(pf); 8491031d839SEric Joyner } 8501031d839SEric Joyner 8511031d839SEric Joyner /* Get the latest mac address... User might use a LAA */ 8521031d839SEric Joyner bcopy(IF_LLADDR(vsi->ifp), tmpaddr, ETH_ALEN); 8531031d839SEric Joyner if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && 8541031d839SEric Joyner (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { 8551031d839SEric Joyner ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 8561031d839SEric Joyner bcopy(tmpaddr, hw->mac.addr, ETH_ALEN); 8571031d839SEric Joyner ret = i40e_aq_mac_address_write(hw, 8581031d839SEric Joyner I40E_AQC_WRITE_TYPE_LAA_ONLY, 8591031d839SEric Joyner hw->mac.addr, NULL); 8601031d839SEric Joyner if (ret) { 8611031d839SEric Joyner device_printf(dev, "LLA address change failed!!\n"); 8621031d839SEric Joyner return; 8631031d839SEric Joyner } 8641031d839SEric Joyner ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); 8651031d839SEric Joyner } 8661031d839SEric Joyner 8671031d839SEric Joyner iflib_set_mac(ctx, hw->mac.addr); 8681031d839SEric Joyner 8691031d839SEric Joyner /* Prepare the VSI: rings, hmc contexts, etc... */ 8701031d839SEric Joyner if (ixl_initialize_vsi(vsi)) { 8711031d839SEric Joyner device_printf(dev, "initialize vsi failed!!\n"); 8721031d839SEric Joyner return; 8731031d839SEric Joyner } 8741031d839SEric Joyner 8751031d839SEric Joyner // TODO: Call iflib setup multicast filters here? 8761031d839SEric Joyner // It's called in ixgbe in D5213 8771031d839SEric Joyner ixl_if_multi_set(ctx); 8781031d839SEric Joyner 8791031d839SEric Joyner /* Set up RSS */ 8801031d839SEric Joyner ixl_config_rss(pf); 8811031d839SEric Joyner 8821031d839SEric Joyner /* Set up MSI/X routing and the ITR settings */ 8831031d839SEric Joyner if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { 8841031d839SEric Joyner ixl_configure_queue_intr_msix(pf); 8851031d839SEric Joyner ixl_configure_itr(pf); 8861031d839SEric Joyner } else 8871031d839SEric Joyner ixl_configure_legacy(pf); 8881031d839SEric Joyner 8891031d839SEric Joyner if (vsi->enable_head_writeback) 8901031d839SEric Joyner ixl_init_tx_cidx(vsi); 8911031d839SEric Joyner else 8921031d839SEric Joyner ixl_init_tx_rsqs(vsi); 8931031d839SEric Joyner 8941031d839SEric Joyner ixl_enable_rings(vsi); 8951031d839SEric Joyner 8961031d839SEric Joyner i40e_aq_set_default_vsi(hw, vsi->seid, NULL); 8971031d839SEric Joyner 8981031d839SEric Joyner ixl_reconfigure_filters(vsi); 8991031d839SEric Joyner 9001031d839SEric Joyner #ifdef IXL_IW 9011031d839SEric Joyner if (ixl_enable_iwarp && pf->iw_enabled) { 9021031d839SEric Joyner ret = ixl_iw_pf_init(pf); 9031031d839SEric Joyner if (ret) 9041031d839SEric Joyner device_printf(dev, 9051031d839SEric Joyner "initialize iwarp failed, code %d\n", ret); 9061031d839SEric Joyner } 9071031d839SEric Joyner #endif 9081031d839SEric Joyner } 9091031d839SEric Joyner 9101031d839SEric Joyner void 9111031d839SEric Joyner ixl_if_stop(if_ctx_t ctx) 9121031d839SEric Joyner { 9131031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 9141031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 9151031d839SEric Joyner 9161031d839SEric Joyner INIT_DEBUGOUT("ixl_if_stop: begin\n"); 9171031d839SEric Joyner 9181031d839SEric Joyner // TODO: This may need to be reworked 9191031d839SEric Joyner #ifdef IXL_IW 9201031d839SEric Joyner /* Stop iWARP device */ 9211031d839SEric Joyner if (ixl_enable_iwarp && pf->iw_enabled) 9221031d839SEric Joyner ixl_iw_pf_stop(pf); 9231031d839SEric Joyner #endif 9241031d839SEric Joyner 9251031d839SEric Joyner ixl_disable_rings_intr(vsi); 9261031d839SEric Joyner ixl_disable_rings(vsi); 9271031d839SEric Joyner } 9281031d839SEric Joyner 9291031d839SEric Joyner static int 9301031d839SEric Joyner ixl_if_msix_intr_assign(if_ctx_t ctx, int msix) 9311031d839SEric Joyner { 9321031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 9331031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 9341031d839SEric Joyner struct ixl_rx_queue *rx_que = vsi->rx_queues; 9351031d839SEric Joyner struct ixl_tx_queue *tx_que = vsi->tx_queues; 9361031d839SEric Joyner int err, i, rid, vector = 0; 9371031d839SEric Joyner char buf[16]; 9381031d839SEric Joyner 9391031d839SEric Joyner /* Admin Que must use vector 0*/ 9401031d839SEric Joyner rid = vector + 1; 9411031d839SEric Joyner err = iflib_irq_alloc_generic(ctx, &vsi->irq, rid, IFLIB_INTR_ADMIN, 9421031d839SEric Joyner ixl_msix_adminq, pf, 0, "aq"); 9431031d839SEric Joyner if (err) { 9441031d839SEric Joyner iflib_irq_free(ctx, &vsi->irq); 9451031d839SEric Joyner device_printf(iflib_get_dev(ctx), 9461031d839SEric Joyner "Failed to register Admin que handler"); 9471031d839SEric Joyner return (err); 9481031d839SEric Joyner } 9491031d839SEric Joyner // TODO: Re-enable this at some point 9501031d839SEric Joyner // iflib_softirq_alloc_generic(ctx, rid, IFLIB_INTR_IOV, pf, 0, "ixl_iov"); 9511031d839SEric Joyner 9521031d839SEric Joyner /* Now set up the stations */ 9531031d839SEric Joyner for (i = 0, vector = 1; i < vsi->num_rx_queues; i++, vector++, rx_que++) { 9541031d839SEric Joyner rid = vector + 1; 9551031d839SEric Joyner 9561031d839SEric Joyner snprintf(buf, sizeof(buf), "rxq%d", i); 9571031d839SEric Joyner err = iflib_irq_alloc_generic(ctx, &rx_que->que_irq, rid, 9581031d839SEric Joyner IFLIB_INTR_RX, ixl_msix_que, rx_que, rx_que->rxr.me, buf); 9591031d839SEric Joyner /* XXX: Does the driver work as expected if there are fewer num_rx_queues than 9601031d839SEric Joyner * what's expected in the iflib context? */ 9611031d839SEric Joyner if (err) { 9621031d839SEric Joyner device_printf(iflib_get_dev(ctx), 9631031d839SEric Joyner "Failed to allocate q int %d err: %d", i, err); 9641031d839SEric Joyner vsi->num_rx_queues = i + 1; 9651031d839SEric Joyner goto fail; 9661031d839SEric Joyner } 9671031d839SEric Joyner rx_que->msix = vector; 9681031d839SEric Joyner } 9691031d839SEric Joyner 9701031d839SEric Joyner bzero(buf, sizeof(buf)); 9711031d839SEric Joyner 9721031d839SEric Joyner for (i = 0; i < vsi->num_tx_queues; i++, tx_que++) { 9731031d839SEric Joyner snprintf(buf, sizeof(buf), "txq%d", i); 9741031d839SEric Joyner iflib_softirq_alloc_generic(ctx, 9751031d839SEric Joyner &vsi->rx_queues[i % vsi->num_rx_queues].que_irq, 9761031d839SEric Joyner IFLIB_INTR_TX, tx_que, tx_que->txr.me, buf); 9771031d839SEric Joyner 9781031d839SEric Joyner /* TODO: Maybe call a strategy function for this to figure out which 9791031d839SEric Joyner * interrupts to map Tx queues to. I don't know if there's an immediately 9801031d839SEric Joyner * better way than this other than a user-supplied map, though. */ 9811031d839SEric Joyner tx_que->msix = (i % vsi->num_rx_queues) + 1; 9821031d839SEric Joyner } 9831031d839SEric Joyner 9841031d839SEric Joyner return (0); 9851031d839SEric Joyner fail: 9861031d839SEric Joyner iflib_irq_free(ctx, &vsi->irq); 9871031d839SEric Joyner rx_que = vsi->rx_queues; 9881031d839SEric Joyner for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) 9891031d839SEric Joyner iflib_irq_free(ctx, &rx_que->que_irq); 9901031d839SEric Joyner return (err); 9911031d839SEric Joyner } 9921031d839SEric Joyner 9931031d839SEric Joyner /* 9941031d839SEric Joyner * Enable all interrupts 9951031d839SEric Joyner * 9961031d839SEric Joyner * Called in: 9971031d839SEric Joyner * iflib_init_locked, after ixl_if_init() 9981031d839SEric Joyner */ 9991031d839SEric Joyner static void 10001031d839SEric Joyner ixl_if_enable_intr(if_ctx_t ctx) 10011031d839SEric Joyner { 10021031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 10031031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 10041031d839SEric Joyner struct i40e_hw *hw = vsi->hw; 10051031d839SEric Joyner struct ixl_rx_queue *que = vsi->rx_queues; 10061031d839SEric Joyner 10071031d839SEric Joyner ixl_enable_intr0(hw); 10081031d839SEric Joyner /* Enable queue interrupts */ 10091031d839SEric Joyner for (int i = 0; i < vsi->num_rx_queues; i++, que++) 10101031d839SEric Joyner /* TODO: Queue index parameter is probably wrong */ 10111031d839SEric Joyner ixl_enable_queue(hw, que->rxr.me); 10121031d839SEric Joyner } 10131031d839SEric Joyner 10141031d839SEric Joyner /* 10151031d839SEric Joyner * Disable queue interrupts 10161031d839SEric Joyner * 10171031d839SEric Joyner * Other interrupt causes need to remain active. 10181031d839SEric Joyner */ 10191031d839SEric Joyner static void 10201031d839SEric Joyner ixl_if_disable_intr(if_ctx_t ctx) 10211031d839SEric Joyner { 10221031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 10231031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 10241031d839SEric Joyner struct i40e_hw *hw = vsi->hw; 10251031d839SEric Joyner struct ixl_rx_queue *rx_que = vsi->rx_queues; 10261031d839SEric Joyner 10271031d839SEric Joyner if (vsi->shared->isc_intr == IFLIB_INTR_MSIX) { 10281031d839SEric Joyner for (int i = 0; i < vsi->num_rx_queues; i++, rx_que++) 10291031d839SEric Joyner ixl_disable_queue(hw, rx_que->msix - 1); 10301031d839SEric Joyner } else { 10311031d839SEric Joyner // Set PFINT_LNKLST0 FIRSTQ_INDX to 0x7FF 10321031d839SEric Joyner // stops queues from triggering interrupts 10331031d839SEric Joyner wr32(hw, I40E_PFINT_LNKLST0, 0x7FF); 10341031d839SEric Joyner } 10351031d839SEric Joyner } 10361031d839SEric Joyner 10371031d839SEric Joyner static int 10381031d839SEric Joyner ixl_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid) 10391031d839SEric Joyner { 10401031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 10411031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 10421031d839SEric Joyner struct i40e_hw *hw = vsi->hw; 10431031d839SEric Joyner struct ixl_rx_queue *rx_que = &vsi->rx_queues[rxqid]; 10441031d839SEric Joyner 10451031d839SEric Joyner ixl_enable_queue(hw, rx_que->msix - 1); 10461031d839SEric Joyner return (0); 10471031d839SEric Joyner } 10481031d839SEric Joyner 10491031d839SEric Joyner static int 10501031d839SEric Joyner ixl_if_tx_queue_intr_enable(if_ctx_t ctx, uint16_t txqid) 10511031d839SEric Joyner { 10521031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 10531031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 10541031d839SEric Joyner struct i40e_hw *hw = vsi->hw; 10551031d839SEric Joyner struct ixl_tx_queue *tx_que = &vsi->tx_queues[txqid]; 10561031d839SEric Joyner 10571031d839SEric Joyner ixl_enable_queue(hw, tx_que->msix - 1); 10581031d839SEric Joyner 10591031d839SEric Joyner return (0); 10601031d839SEric Joyner } 10611031d839SEric Joyner 10621031d839SEric Joyner static int 10631031d839SEric Joyner ixl_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets) 10641031d839SEric Joyner { 10651031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 10661031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 10671031d839SEric Joyner if_softc_ctx_t scctx = vsi->shared; 10681031d839SEric Joyner struct ixl_tx_queue *que; 10691031d839SEric Joyner // int i; 10701031d839SEric Joyner int i, j, error = 0; 10711031d839SEric Joyner 10721031d839SEric Joyner MPASS(vsi->num_tx_queues > 0); 10731031d839SEric Joyner MPASS(ntxqs == 1); 10741031d839SEric Joyner MPASS(vsi->num_tx_queues == ntxqsets); 10751031d839SEric Joyner 10761031d839SEric Joyner /* Allocate queue structure memory */ 10771031d839SEric Joyner if (!(vsi->tx_queues = 10781031d839SEric Joyner (struct ixl_tx_queue *) malloc(sizeof(struct ixl_tx_queue) *ntxqsets, M_IXL, M_NOWAIT | M_ZERO))) { 10791031d839SEric Joyner device_printf(iflib_get_dev(ctx), "Unable to allocate TX ring memory\n"); 10801031d839SEric Joyner return (ENOMEM); 10811031d839SEric Joyner } 10821031d839SEric Joyner 10831031d839SEric Joyner for (i = 0, que = vsi->tx_queues; i < ntxqsets; i++, que++) { 10841031d839SEric Joyner struct tx_ring *txr = &que->txr; 10851031d839SEric Joyner 10861031d839SEric Joyner txr->me = i; 10871031d839SEric Joyner que->vsi = vsi; 10881031d839SEric Joyner 10891031d839SEric Joyner if (!vsi->enable_head_writeback) { 10901031d839SEric Joyner /* Allocate report status array */ 10911031d839SEric Joyner if (!(txr->tx_rsq = malloc(sizeof(qidx_t) * scctx->isc_ntxd[0], M_IXL, M_NOWAIT))) { 10921031d839SEric Joyner device_printf(iflib_get_dev(ctx), "failed to allocate tx_rsq memory\n"); 10931031d839SEric Joyner error = ENOMEM; 10941031d839SEric Joyner goto fail; 10951031d839SEric Joyner } 10961031d839SEric Joyner /* Init report status array */ 10971031d839SEric Joyner for (j = 0; j < scctx->isc_ntxd[0]; j++) 10981031d839SEric Joyner txr->tx_rsq[j] = QIDX_INVALID; 10991031d839SEric Joyner } 11001031d839SEric Joyner /* get the virtual and physical address of the hardware queues */ 11011031d839SEric Joyner txr->tail = I40E_QTX_TAIL(txr->me); 11021031d839SEric Joyner txr->tx_base = (struct i40e_tx_desc *)vaddrs[i * ntxqs]; 11031031d839SEric Joyner txr->tx_paddr = paddrs[i * ntxqs]; 11041031d839SEric Joyner txr->que = que; 11051031d839SEric Joyner } 11061031d839SEric Joyner 11071031d839SEric Joyner return (0); 11081031d839SEric Joyner fail: 11091031d839SEric Joyner ixl_if_queues_free(ctx); 11101031d839SEric Joyner return (error); 11111031d839SEric Joyner } 11121031d839SEric Joyner 11131031d839SEric Joyner static int 11141031d839SEric Joyner ixl_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs, int nrxqsets) 11151031d839SEric Joyner { 11161031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 11171031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 11181031d839SEric Joyner struct ixl_rx_queue *que; 11191031d839SEric Joyner int i, error = 0; 11201031d839SEric Joyner 11211031d839SEric Joyner MPASS(vsi->num_rx_queues > 0); 11221031d839SEric Joyner MPASS(nrxqs == 1); 11231031d839SEric Joyner MPASS(vsi->num_rx_queues == nrxqsets); 11241031d839SEric Joyner 11251031d839SEric Joyner /* Allocate queue structure memory */ 11261031d839SEric Joyner if (!(vsi->rx_queues = 11271031d839SEric Joyner (struct ixl_rx_queue *) malloc(sizeof(struct ixl_rx_queue) * 11281031d839SEric Joyner nrxqsets, M_IXL, M_NOWAIT | M_ZERO))) { 11291031d839SEric Joyner device_printf(iflib_get_dev(ctx), "Unable to allocate RX ring memory\n"); 11301031d839SEric Joyner error = ENOMEM; 11311031d839SEric Joyner goto fail; 11321031d839SEric Joyner } 11331031d839SEric Joyner 11341031d839SEric Joyner for (i = 0, que = vsi->rx_queues; i < nrxqsets; i++, que++) { 11351031d839SEric Joyner struct rx_ring *rxr = &que->rxr; 11361031d839SEric Joyner 11371031d839SEric Joyner rxr->me = i; 11381031d839SEric Joyner que->vsi = vsi; 11391031d839SEric Joyner 11401031d839SEric Joyner /* get the virtual and physical address of the hardware queues */ 11411031d839SEric Joyner rxr->tail = I40E_QRX_TAIL(rxr->me); 11421031d839SEric Joyner rxr->rx_base = (union i40e_rx_desc *)vaddrs[i * nrxqs]; 11431031d839SEric Joyner rxr->rx_paddr = paddrs[i * nrxqs]; 11441031d839SEric Joyner rxr->que = que; 11451031d839SEric Joyner } 11461031d839SEric Joyner 11471031d839SEric Joyner return (0); 11481031d839SEric Joyner fail: 11491031d839SEric Joyner ixl_if_queues_free(ctx); 11501031d839SEric Joyner return (error); 11511031d839SEric Joyner } 11521031d839SEric Joyner 11531031d839SEric Joyner static void 11541031d839SEric Joyner ixl_if_queues_free(if_ctx_t ctx) 11551031d839SEric Joyner { 11561031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 11571031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 11581031d839SEric Joyner 11591031d839SEric Joyner if (vsi->enable_head_writeback) { 11601031d839SEric Joyner struct ixl_tx_queue *que; 11611031d839SEric Joyner int i = 0; 11621031d839SEric Joyner 11631031d839SEric Joyner for (i = 0, que = vsi->tx_queues; i < vsi->num_tx_queues; i++, que++) { 11641031d839SEric Joyner struct tx_ring *txr = &que->txr; 11651031d839SEric Joyner if (txr->tx_rsq != NULL) { 11661031d839SEric Joyner free(txr->tx_rsq, M_IXL); 11671031d839SEric Joyner txr->tx_rsq = NULL; 11681031d839SEric Joyner } 11691031d839SEric Joyner } 11701031d839SEric Joyner } 11711031d839SEric Joyner 11721031d839SEric Joyner if (vsi->tx_queues != NULL) { 11731031d839SEric Joyner free(vsi->tx_queues, M_IXL); 11741031d839SEric Joyner vsi->tx_queues = NULL; 11751031d839SEric Joyner } 11761031d839SEric Joyner if (vsi->rx_queues != NULL) { 11771031d839SEric Joyner free(vsi->rx_queues, M_IXL); 11781031d839SEric Joyner vsi->rx_queues = NULL; 11791031d839SEric Joyner } 11801031d839SEric Joyner } 11811031d839SEric Joyner 11821031d839SEric Joyner void 11831031d839SEric Joyner ixl_update_link_status(struct ixl_pf *pf) 11841031d839SEric Joyner { 11851031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 1186c9da8d8bSEric Joyner struct i40e_hw *hw = &pf->hw; 11871031d839SEric Joyner u64 baudrate; 11881031d839SEric Joyner 11891031d839SEric Joyner if (pf->link_up) { 11901031d839SEric Joyner if (vsi->link_active == FALSE) { 11911031d839SEric Joyner vsi->link_active = TRUE; 1192c9da8d8bSEric Joyner baudrate = ixl_max_aq_speed_to_value(hw->phy.link_info.link_speed); 11931031d839SEric Joyner iflib_link_state_change(vsi->ctx, LINK_STATE_UP, baudrate); 11941031d839SEric Joyner ixl_link_up_msg(pf); 11951031d839SEric Joyner #ifdef PCI_IOV 11961031d839SEric Joyner ixl_broadcast_link_state(pf); 11971031d839SEric Joyner #endif 11981031d839SEric Joyner 11991031d839SEric Joyner } 12001031d839SEric Joyner } else { /* Link down */ 12011031d839SEric Joyner if (vsi->link_active == TRUE) { 12021031d839SEric Joyner vsi->link_active = FALSE; 12031031d839SEric Joyner iflib_link_state_change(vsi->ctx, LINK_STATE_DOWN, 0); 12041031d839SEric Joyner #ifdef PCI_IOV 12051031d839SEric Joyner ixl_broadcast_link_state(pf); 12061031d839SEric Joyner #endif 12071031d839SEric Joyner } 12081031d839SEric Joyner } 12091031d839SEric Joyner } 12101031d839SEric Joyner 12111031d839SEric Joyner static int 12121031d839SEric Joyner ixl_process_adminq(struct ixl_pf *pf, u16 *pending) 12131031d839SEric Joyner { 12141031d839SEric Joyner enum i40e_status_code status = I40E_SUCCESS; 12151031d839SEric Joyner struct i40e_arq_event_info event; 12161031d839SEric Joyner struct i40e_hw *hw = &pf->hw; 12171031d839SEric Joyner device_t dev = pf->dev; 12181031d839SEric Joyner u16 opcode; 12191031d839SEric Joyner u32 loop = 0, reg; 12201031d839SEric Joyner 12211031d839SEric Joyner event.buf_len = IXL_AQ_BUF_SZ; 12221031d839SEric Joyner event.msg_buf = malloc(event.buf_len, M_IXL, M_NOWAIT | M_ZERO); 12231031d839SEric Joyner if (!event.msg_buf) { 12241031d839SEric Joyner device_printf(dev, "%s: Unable to allocate memory for Admin" 12251031d839SEric Joyner " Queue event!\n", __func__); 12261031d839SEric Joyner return (ENOMEM); 12271031d839SEric Joyner } 12281031d839SEric Joyner 12291031d839SEric Joyner /* clean and process any events */ 12301031d839SEric Joyner do { 12311031d839SEric Joyner status = i40e_clean_arq_element(hw, &event, pending); 12321031d839SEric Joyner if (status) 12331031d839SEric Joyner break; 12341031d839SEric Joyner opcode = LE16_TO_CPU(event.desc.opcode); 12351031d839SEric Joyner ixl_dbg(pf, IXL_DBG_AQ, 12361031d839SEric Joyner "Admin Queue event: %#06x\n", opcode); 12371031d839SEric Joyner switch (opcode) { 12381031d839SEric Joyner case i40e_aqc_opc_get_link_status: 12391031d839SEric Joyner ixl_link_event(pf, &event); 12401031d839SEric Joyner break; 12411031d839SEric Joyner case i40e_aqc_opc_send_msg_to_pf: 12421031d839SEric Joyner #ifdef PCI_IOV 12431031d839SEric Joyner ixl_handle_vf_msg(pf, &event); 12441031d839SEric Joyner #endif 12451031d839SEric Joyner break; 12461031d839SEric Joyner /* 12471031d839SEric Joyner * This should only occur on no-drop queues, which 12481031d839SEric Joyner * aren't currently configured. 12491031d839SEric Joyner */ 12501031d839SEric Joyner case i40e_aqc_opc_event_lan_overflow: 12511031d839SEric Joyner device_printf(dev, "LAN overflow event\n"); 12521031d839SEric Joyner break; 12531031d839SEric Joyner default: 12541031d839SEric Joyner break; 12551031d839SEric Joyner } 12561031d839SEric Joyner } while (*pending && (loop++ < IXL_ADM_LIMIT)); 12571031d839SEric Joyner 12581031d839SEric Joyner free(event.msg_buf, M_IXL); 12591031d839SEric Joyner 12601031d839SEric Joyner /* Re-enable admin queue interrupt cause */ 12611031d839SEric Joyner reg = rd32(hw, I40E_PFINT_ICR0_ENA); 12621031d839SEric Joyner reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK; 12631031d839SEric Joyner wr32(hw, I40E_PFINT_ICR0_ENA, reg); 12641031d839SEric Joyner 12651031d839SEric Joyner return (status); 12661031d839SEric Joyner } 12671031d839SEric Joyner 12681031d839SEric Joyner static void 12691031d839SEric Joyner ixl_if_update_admin_status(if_ctx_t ctx) 12701031d839SEric Joyner { 12711031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 12721031d839SEric Joyner struct i40e_hw *hw = &pf->hw; 12731031d839SEric Joyner u16 pending; 12741031d839SEric Joyner 12751031d839SEric Joyner if (pf->state & IXL_PF_STATE_ADAPTER_RESETTING) 12761031d839SEric Joyner ixl_handle_empr_reset(pf); 12771031d839SEric Joyner 12781031d839SEric Joyner if (pf->state & IXL_PF_STATE_MDD_PENDING) 12791031d839SEric Joyner ixl_handle_mdd_event(pf); 12801031d839SEric Joyner 12811031d839SEric Joyner #ifdef PCI_IOV 12821031d839SEric Joyner if (pf->state & IXL_PF_STATE_VF_RESET_REQ) 12831031d839SEric Joyner iflib_iov_intr_deferred(ctx); 12841031d839SEric Joyner #endif 12851031d839SEric Joyner 12861031d839SEric Joyner ixl_process_adminq(pf, &pending); 12871031d839SEric Joyner ixl_update_link_status(pf); 12881031d839SEric Joyner 12891031d839SEric Joyner /* 12901031d839SEric Joyner * If there are still messages to process, reschedule ourselves. 12911031d839SEric Joyner * Otherwise, re-enable our interrupt and go to sleep. 12921031d839SEric Joyner */ 12931031d839SEric Joyner if (pending > 0) 12941031d839SEric Joyner iflib_admin_intr_deferred(ctx); 12951031d839SEric Joyner else 12961031d839SEric Joyner ixl_enable_intr0(hw); 12971031d839SEric Joyner } 12981031d839SEric Joyner 12991031d839SEric Joyner static void 13001031d839SEric Joyner ixl_if_multi_set(if_ctx_t ctx) 13011031d839SEric Joyner { 13021031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 13031031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 13041031d839SEric Joyner struct i40e_hw *hw = vsi->hw; 13051031d839SEric Joyner int mcnt = 0, flags; 13061031d839SEric Joyner 13071031d839SEric Joyner IOCTL_DEBUGOUT("ixl_if_multi_set: begin"); 13081031d839SEric Joyner 13091031d839SEric Joyner mcnt = if_multiaddr_count(iflib_get_ifp(ctx), MAX_MULTICAST_ADDR); 13101031d839SEric Joyner /* delete existing MC filters */ 13111031d839SEric Joyner ixl_del_multi(vsi); 13121031d839SEric Joyner 13131031d839SEric Joyner if (__predict_false(mcnt == MAX_MULTICAST_ADDR)) { 13141031d839SEric Joyner i40e_aq_set_vsi_multicast_promiscuous(hw, 13151031d839SEric Joyner vsi->seid, TRUE, NULL); 13161031d839SEric Joyner return; 13171031d839SEric Joyner } 13181031d839SEric Joyner /* (re-)install filters for all mcast addresses */ 13191031d839SEric Joyner mcnt = if_multi_apply(iflib_get_ifp(ctx), ixl_mc_filter_apply, vsi); 13201031d839SEric Joyner 13211031d839SEric Joyner if (mcnt > 0) { 13221031d839SEric Joyner flags = (IXL_FILTER_ADD | IXL_FILTER_USED | IXL_FILTER_MC); 13231031d839SEric Joyner ixl_add_hw_filters(vsi, flags, mcnt); 13241031d839SEric Joyner } 13251031d839SEric Joyner 13261031d839SEric Joyner IOCTL_DEBUGOUT("ixl_if_multi_set: end"); 13271031d839SEric Joyner } 13281031d839SEric Joyner 13291031d839SEric Joyner static int 13301031d839SEric Joyner ixl_if_mtu_set(if_ctx_t ctx, uint32_t mtu) 13311031d839SEric Joyner { 13321031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 13331031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 13341031d839SEric Joyner 13351031d839SEric Joyner IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); 13361031d839SEric Joyner if (mtu > IXL_MAX_FRAME - ETHER_HDR_LEN - ETHER_CRC_LEN - 13371031d839SEric Joyner ETHER_VLAN_ENCAP_LEN) 13381031d839SEric Joyner return (EINVAL); 13391031d839SEric Joyner 13401031d839SEric Joyner vsi->shared->isc_max_frame_size = mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + 13411031d839SEric Joyner ETHER_VLAN_ENCAP_LEN; 13421031d839SEric Joyner 13431031d839SEric Joyner return (0); 13441031d839SEric Joyner } 13451031d839SEric Joyner 13461031d839SEric Joyner static void 13471031d839SEric Joyner ixl_if_media_status(if_ctx_t ctx, struct ifmediareq *ifmr) 13481031d839SEric Joyner { 13491031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 13501031d839SEric Joyner struct i40e_hw *hw = &pf->hw; 13511031d839SEric Joyner 13521031d839SEric Joyner INIT_DEBUGOUT("ixl_media_status: begin"); 13531031d839SEric Joyner 13541031d839SEric Joyner ifmr->ifm_status = IFM_AVALID; 13551031d839SEric Joyner ifmr->ifm_active = IFM_ETHER; 13561031d839SEric Joyner 13571031d839SEric Joyner if (!pf->link_up) { 13581031d839SEric Joyner return; 13591031d839SEric Joyner } 13601031d839SEric Joyner 13611031d839SEric Joyner ifmr->ifm_status |= IFM_ACTIVE; 13621031d839SEric Joyner /* Hardware is always full-duplex */ 13631031d839SEric Joyner ifmr->ifm_active |= IFM_FDX; 13641031d839SEric Joyner 13651031d839SEric Joyner switch (hw->phy.link_info.phy_type) { 13661031d839SEric Joyner /* 100 M */ 13671031d839SEric Joyner case I40E_PHY_TYPE_100BASE_TX: 13681031d839SEric Joyner ifmr->ifm_active |= IFM_100_TX; 13691031d839SEric Joyner break; 13701031d839SEric Joyner /* 1 G */ 13711031d839SEric Joyner case I40E_PHY_TYPE_1000BASE_T: 13721031d839SEric Joyner ifmr->ifm_active |= IFM_1000_T; 13731031d839SEric Joyner break; 13741031d839SEric Joyner case I40E_PHY_TYPE_1000BASE_SX: 13751031d839SEric Joyner ifmr->ifm_active |= IFM_1000_SX; 13761031d839SEric Joyner break; 13771031d839SEric Joyner case I40E_PHY_TYPE_1000BASE_LX: 13781031d839SEric Joyner ifmr->ifm_active |= IFM_1000_LX; 13791031d839SEric Joyner break; 13801031d839SEric Joyner case I40E_PHY_TYPE_1000BASE_T_OPTICAL: 13811031d839SEric Joyner ifmr->ifm_active |= IFM_1000_T; 13821031d839SEric Joyner break; 13831031d839SEric Joyner /* 10 G */ 13841031d839SEric Joyner case I40E_PHY_TYPE_10GBASE_SFPP_CU: 13851031d839SEric Joyner ifmr->ifm_active |= IFM_10G_TWINAX; 13861031d839SEric Joyner break; 13871031d839SEric Joyner case I40E_PHY_TYPE_10GBASE_SR: 13881031d839SEric Joyner ifmr->ifm_active |= IFM_10G_SR; 13891031d839SEric Joyner break; 13901031d839SEric Joyner case I40E_PHY_TYPE_10GBASE_LR: 13911031d839SEric Joyner ifmr->ifm_active |= IFM_10G_LR; 13921031d839SEric Joyner break; 13931031d839SEric Joyner case I40E_PHY_TYPE_10GBASE_T: 13941031d839SEric Joyner ifmr->ifm_active |= IFM_10G_T; 13951031d839SEric Joyner break; 13961031d839SEric Joyner case I40E_PHY_TYPE_XAUI: 13971031d839SEric Joyner case I40E_PHY_TYPE_XFI: 13981031d839SEric Joyner ifmr->ifm_active |= IFM_10G_TWINAX; 13991031d839SEric Joyner break; 14001031d839SEric Joyner case I40E_PHY_TYPE_10GBASE_AOC: 14011031d839SEric Joyner ifmr->ifm_active |= IFM_10G_AOC; 14021031d839SEric Joyner break; 14031031d839SEric Joyner /* 25 G */ 14041031d839SEric Joyner case I40E_PHY_TYPE_25GBASE_KR: 14051031d839SEric Joyner ifmr->ifm_active |= IFM_25G_KR; 14061031d839SEric Joyner break; 14071031d839SEric Joyner case I40E_PHY_TYPE_25GBASE_CR: 14081031d839SEric Joyner ifmr->ifm_active |= IFM_25G_CR; 14091031d839SEric Joyner break; 14101031d839SEric Joyner case I40E_PHY_TYPE_25GBASE_SR: 14111031d839SEric Joyner ifmr->ifm_active |= IFM_25G_SR; 14121031d839SEric Joyner break; 14131031d839SEric Joyner case I40E_PHY_TYPE_25GBASE_LR: 14141031d839SEric Joyner ifmr->ifm_active |= IFM_25G_LR; 14151031d839SEric Joyner break; 14161031d839SEric Joyner case I40E_PHY_TYPE_25GBASE_AOC: 14171031d839SEric Joyner ifmr->ifm_active |= IFM_25G_AOC; 14181031d839SEric Joyner break; 14191031d839SEric Joyner case I40E_PHY_TYPE_25GBASE_ACC: 14201031d839SEric Joyner ifmr->ifm_active |= IFM_25G_ACC; 14211031d839SEric Joyner break; 14221031d839SEric Joyner /* 40 G */ 14231031d839SEric Joyner case I40E_PHY_TYPE_40GBASE_CR4: 14241031d839SEric Joyner case I40E_PHY_TYPE_40GBASE_CR4_CU: 14251031d839SEric Joyner ifmr->ifm_active |= IFM_40G_CR4; 14261031d839SEric Joyner break; 14271031d839SEric Joyner case I40E_PHY_TYPE_40GBASE_SR4: 14281031d839SEric Joyner ifmr->ifm_active |= IFM_40G_SR4; 14291031d839SEric Joyner break; 14301031d839SEric Joyner case I40E_PHY_TYPE_40GBASE_LR4: 14311031d839SEric Joyner ifmr->ifm_active |= IFM_40G_LR4; 14321031d839SEric Joyner break; 14331031d839SEric Joyner case I40E_PHY_TYPE_XLAUI: 14341031d839SEric Joyner ifmr->ifm_active |= IFM_OTHER; 14351031d839SEric Joyner break; 14361031d839SEric Joyner case I40E_PHY_TYPE_1000BASE_KX: 14371031d839SEric Joyner ifmr->ifm_active |= IFM_1000_KX; 14381031d839SEric Joyner break; 14391031d839SEric Joyner case I40E_PHY_TYPE_SGMII: 14401031d839SEric Joyner ifmr->ifm_active |= IFM_1000_SGMII; 14411031d839SEric Joyner break; 14421031d839SEric Joyner /* ERJ: What's the difference between these? */ 14431031d839SEric Joyner case I40E_PHY_TYPE_10GBASE_CR1_CU: 14441031d839SEric Joyner case I40E_PHY_TYPE_10GBASE_CR1: 14451031d839SEric Joyner ifmr->ifm_active |= IFM_10G_CR1; 14461031d839SEric Joyner break; 14471031d839SEric Joyner case I40E_PHY_TYPE_10GBASE_KX4: 14481031d839SEric Joyner ifmr->ifm_active |= IFM_10G_KX4; 14491031d839SEric Joyner break; 14501031d839SEric Joyner case I40E_PHY_TYPE_10GBASE_KR: 14511031d839SEric Joyner ifmr->ifm_active |= IFM_10G_KR; 14521031d839SEric Joyner break; 14531031d839SEric Joyner case I40E_PHY_TYPE_SFI: 14541031d839SEric Joyner ifmr->ifm_active |= IFM_10G_SFI; 14551031d839SEric Joyner break; 14561031d839SEric Joyner /* Our single 20G media type */ 14571031d839SEric Joyner case I40E_PHY_TYPE_20GBASE_KR2: 14581031d839SEric Joyner ifmr->ifm_active |= IFM_20G_KR2; 14591031d839SEric Joyner break; 14601031d839SEric Joyner case I40E_PHY_TYPE_40GBASE_KR4: 14611031d839SEric Joyner ifmr->ifm_active |= IFM_40G_KR4; 14621031d839SEric Joyner break; 14631031d839SEric Joyner case I40E_PHY_TYPE_XLPPI: 14641031d839SEric Joyner case I40E_PHY_TYPE_40GBASE_AOC: 14651031d839SEric Joyner ifmr->ifm_active |= IFM_40G_XLPPI; 14661031d839SEric Joyner break; 14671031d839SEric Joyner /* Unknown to driver */ 14681031d839SEric Joyner default: 14691031d839SEric Joyner ifmr->ifm_active |= IFM_UNKNOWN; 14701031d839SEric Joyner break; 14711031d839SEric Joyner } 14721031d839SEric Joyner /* Report flow control status as well */ 14731031d839SEric Joyner if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) 14741031d839SEric Joyner ifmr->ifm_active |= IFM_ETH_TXPAUSE; 14751031d839SEric Joyner if (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) 14761031d839SEric Joyner ifmr->ifm_active |= IFM_ETH_RXPAUSE; 14771031d839SEric Joyner } 14781031d839SEric Joyner 14791031d839SEric Joyner static int 14801031d839SEric Joyner ixl_if_media_change(if_ctx_t ctx) 14811031d839SEric Joyner { 14821031d839SEric Joyner struct ifmedia *ifm = iflib_get_media(ctx); 14831031d839SEric Joyner 14841031d839SEric Joyner INIT_DEBUGOUT("ixl_media_change: begin"); 14851031d839SEric Joyner 14861031d839SEric Joyner if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 14871031d839SEric Joyner return (EINVAL); 14881031d839SEric Joyner 14891031d839SEric Joyner if_printf(iflib_get_ifp(ctx), "Media change is not supported.\n"); 14901031d839SEric Joyner return (ENODEV); 14911031d839SEric Joyner } 14921031d839SEric Joyner 14931031d839SEric Joyner static int 14941031d839SEric Joyner ixl_if_promisc_set(if_ctx_t ctx, int flags) 14951031d839SEric Joyner { 14961031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 14971031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 14981031d839SEric Joyner struct ifnet *ifp = iflib_get_ifp(ctx); 14991031d839SEric Joyner struct i40e_hw *hw = vsi->hw; 15001031d839SEric Joyner int err; 15011031d839SEric Joyner bool uni = FALSE, multi = FALSE; 15021031d839SEric Joyner 15031031d839SEric Joyner if (flags & IFF_PROMISC) 15041031d839SEric Joyner uni = multi = TRUE; 15051031d839SEric Joyner else if (flags & IFF_ALLMULTI || 15061031d839SEric Joyner if_multiaddr_count(ifp, MAX_MULTICAST_ADDR) == MAX_MULTICAST_ADDR) 15071031d839SEric Joyner multi = TRUE; 15081031d839SEric Joyner 15091031d839SEric Joyner err = i40e_aq_set_vsi_unicast_promiscuous(hw, 15101031d839SEric Joyner vsi->seid, uni, NULL, true); 15111031d839SEric Joyner if (err) 15121031d839SEric Joyner return (err); 15131031d839SEric Joyner err = i40e_aq_set_vsi_multicast_promiscuous(hw, 15141031d839SEric Joyner vsi->seid, multi, NULL); 15151031d839SEric Joyner return (err); 15161031d839SEric Joyner } 15171031d839SEric Joyner 15181031d839SEric Joyner static void 15191031d839SEric Joyner ixl_if_timer(if_ctx_t ctx, uint16_t qid) 15201031d839SEric Joyner { 15211031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 15221031d839SEric Joyner //struct i40e_hw *hw = &pf->hw; 15231031d839SEric Joyner //struct ixl_tx_queue *que = &vsi->tx_queues[qid]; 15241031d839SEric Joyner #if 0 15251031d839SEric Joyner u32 mask; 15261031d839SEric Joyner 15271031d839SEric Joyner /* 15281031d839SEric Joyner ** Check status of the queues 15291031d839SEric Joyner */ 15301031d839SEric Joyner mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | 15311031d839SEric Joyner I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); 15321031d839SEric Joyner 15331031d839SEric Joyner /* If queue param has outstanding work, trigger sw irq */ 15341031d839SEric Joyner // TODO: TX queues in iflib don't use HW interrupts; does this do anything? 15351031d839SEric Joyner if (que->busy) 15361031d839SEric Joyner wr32(hw, I40E_PFINT_DYN_CTLN(que->txr.me), mask); 15371031d839SEric Joyner #endif 15381031d839SEric Joyner 15391031d839SEric Joyner if (qid != 0) 15401031d839SEric Joyner return; 15411031d839SEric Joyner 15421031d839SEric Joyner /* Fire off the adminq task */ 15431031d839SEric Joyner iflib_admin_intr_deferred(ctx); 15441031d839SEric Joyner 15451031d839SEric Joyner /* Update stats */ 15461031d839SEric Joyner ixl_update_stats_counters(pf); 15471031d839SEric Joyner } 15481031d839SEric Joyner 15491031d839SEric Joyner static void 15501031d839SEric Joyner ixl_if_vlan_register(if_ctx_t ctx, u16 vtag) 15511031d839SEric Joyner { 15521031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 15531031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 15541031d839SEric Joyner struct i40e_hw *hw = vsi->hw; 15551031d839SEric Joyner 15561031d839SEric Joyner if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 15571031d839SEric Joyner return; 15581031d839SEric Joyner 15591031d839SEric Joyner ++vsi->num_vlans; 15601031d839SEric Joyner ixl_add_filter(vsi, hw->mac.addr, vtag); 15611031d839SEric Joyner } 15621031d839SEric Joyner 15631031d839SEric Joyner static void 15641031d839SEric Joyner ixl_if_vlan_unregister(if_ctx_t ctx, u16 vtag) 15651031d839SEric Joyner { 15661031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 15671031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 15681031d839SEric Joyner struct i40e_hw *hw = vsi->hw; 15691031d839SEric Joyner 15701031d839SEric Joyner if ((vtag == 0) || (vtag > 4095)) /* Invalid */ 15711031d839SEric Joyner return; 15721031d839SEric Joyner 15731031d839SEric Joyner --vsi->num_vlans; 15741031d839SEric Joyner ixl_del_filter(vsi, hw->mac.addr, vtag); 15751031d839SEric Joyner } 15761031d839SEric Joyner 15771031d839SEric Joyner static uint64_t 15781031d839SEric Joyner ixl_if_get_counter(if_ctx_t ctx, ift_counter cnt) 15791031d839SEric Joyner { 15801031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 15811031d839SEric Joyner struct ixl_vsi *vsi = &pf->vsi; 15821031d839SEric Joyner if_t ifp = iflib_get_ifp(ctx); 15831031d839SEric Joyner 15841031d839SEric Joyner switch (cnt) { 15851031d839SEric Joyner case IFCOUNTER_IPACKETS: 15861031d839SEric Joyner return (vsi->ipackets); 15871031d839SEric Joyner case IFCOUNTER_IERRORS: 15881031d839SEric Joyner return (vsi->ierrors); 15891031d839SEric Joyner case IFCOUNTER_OPACKETS: 15901031d839SEric Joyner return (vsi->opackets); 15911031d839SEric Joyner case IFCOUNTER_OERRORS: 15921031d839SEric Joyner return (vsi->oerrors); 15931031d839SEric Joyner case IFCOUNTER_COLLISIONS: 15941031d839SEric Joyner /* Collisions are by standard impossible in 40G/10G Ethernet */ 15951031d839SEric Joyner return (0); 15961031d839SEric Joyner case IFCOUNTER_IBYTES: 15971031d839SEric Joyner return (vsi->ibytes); 15981031d839SEric Joyner case IFCOUNTER_OBYTES: 15991031d839SEric Joyner return (vsi->obytes); 16001031d839SEric Joyner case IFCOUNTER_IMCASTS: 16011031d839SEric Joyner return (vsi->imcasts); 16021031d839SEric Joyner case IFCOUNTER_OMCASTS: 16031031d839SEric Joyner return (vsi->omcasts); 16041031d839SEric Joyner case IFCOUNTER_IQDROPS: 16051031d839SEric Joyner return (vsi->iqdrops); 16061031d839SEric Joyner case IFCOUNTER_OQDROPS: 16071031d839SEric Joyner return (vsi->oqdrops); 16081031d839SEric Joyner case IFCOUNTER_NOPROTO: 16091031d839SEric Joyner return (vsi->noproto); 16101031d839SEric Joyner default: 16111031d839SEric Joyner return (if_get_counter_default(ifp, cnt)); 16121031d839SEric Joyner } 16131031d839SEric Joyner } 16141031d839SEric Joyner 16151031d839SEric Joyner static void 16161031d839SEric Joyner ixl_if_vflr_handle(if_ctx_t ctx) 16171031d839SEric Joyner { 16181031d839SEric Joyner IXL_DEV_ERR(iflib_get_dev(ctx), ""); 16191031d839SEric Joyner 16201031d839SEric Joyner // TODO: call ixl_handle_vflr() 16211031d839SEric Joyner } 16221031d839SEric Joyner 16231031d839SEric Joyner static int 16241031d839SEric Joyner ixl_if_i2c_req(if_ctx_t ctx, struct ifi2creq *req) 16251031d839SEric Joyner { 16261031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 16271031d839SEric Joyner 16281031d839SEric Joyner if (pf->read_i2c_byte == NULL) 16291031d839SEric Joyner return (EINVAL); 16301031d839SEric Joyner 16311031d839SEric Joyner for (int i = 0; i < req->len; i++) 16321031d839SEric Joyner if (pf->read_i2c_byte(pf, req->offset + i, 16331031d839SEric Joyner req->dev_addr, &req->data[i])) 16341031d839SEric Joyner return (EIO); 16351031d839SEric Joyner return (0); 16361031d839SEric Joyner } 16371031d839SEric Joyner 16381031d839SEric Joyner static int 16391031d839SEric Joyner ixl_if_priv_ioctl(if_ctx_t ctx, u_long command, caddr_t data) 16401031d839SEric Joyner { 16411031d839SEric Joyner struct ixl_pf *pf = iflib_get_softc(ctx); 16421031d839SEric Joyner struct ifdrv *ifd = (struct ifdrv *)data; 16431031d839SEric Joyner int error = 0; 16441031d839SEric Joyner 16451031d839SEric Joyner /* NVM update command */ 16461031d839SEric Joyner if (ifd->ifd_cmd == I40E_NVM_ACCESS) 16471031d839SEric Joyner error = ixl_handle_nvmupd_cmd(pf, ifd); 16481031d839SEric Joyner else 16491031d839SEric Joyner error = EINVAL; 16501031d839SEric Joyner 16511031d839SEric Joyner return (error); 16521031d839SEric Joyner } 16531031d839SEric Joyner 16541031d839SEric Joyner static int 16551031d839SEric Joyner ixl_mc_filter_apply(void *arg, struct ifmultiaddr *ifma, int count __unused) 16561031d839SEric Joyner { 16571031d839SEric Joyner struct ixl_vsi *vsi = arg; 16581031d839SEric Joyner 16591031d839SEric Joyner if (ifma->ifma_addr->sa_family != AF_LINK) 16601031d839SEric Joyner return (0); 16611031d839SEric Joyner ixl_add_mc_filter(vsi, 16621031d839SEric Joyner (u8*)LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); 16631031d839SEric Joyner return (1); 16641031d839SEric Joyner } 16651031d839SEric Joyner 16661031d839SEric Joyner /* 16671031d839SEric Joyner * Sanity check and save off tunable values. 16681031d839SEric Joyner */ 16691031d839SEric Joyner static void 16701031d839SEric Joyner ixl_save_pf_tunables(struct ixl_pf *pf) 16711031d839SEric Joyner { 16721031d839SEric Joyner device_t dev = pf->dev; 16731031d839SEric Joyner 16741031d839SEric Joyner /* Save tunable information */ 16751031d839SEric Joyner pf->enable_tx_fc_filter = ixl_enable_tx_fc_filter; 16761031d839SEric Joyner pf->dbg_mask = ixl_core_debug_mask; 16771031d839SEric Joyner pf->hw.debug_mask = ixl_shared_debug_mask; 16781031d839SEric Joyner pf->vsi.enable_head_writeback = !!(ixl_enable_head_writeback); 16791031d839SEric Joyner #if 0 16801031d839SEric Joyner pf->dynamic_rx_itr = ixl_dynamic_rx_itr; 16811031d839SEric Joyner pf->dynamic_tx_itr = ixl_dynamic_tx_itr; 16821031d839SEric Joyner #endif 16831031d839SEric Joyner 16841031d839SEric Joyner if (ixl_i2c_access_method > 3 || ixl_i2c_access_method < 0) 16851031d839SEric Joyner pf->i2c_access_method = 0; 16861031d839SEric Joyner else 16871031d839SEric Joyner pf->i2c_access_method = ixl_i2c_access_method; 16881031d839SEric Joyner 16891031d839SEric Joyner if (ixl_tx_itr < 0 || ixl_tx_itr > IXL_MAX_ITR) { 16901031d839SEric Joyner device_printf(dev, "Invalid tx_itr value of %d set!\n", 16911031d839SEric Joyner ixl_tx_itr); 16921031d839SEric Joyner device_printf(dev, "tx_itr must be between %d and %d, " 16931031d839SEric Joyner "inclusive\n", 16941031d839SEric Joyner 0, IXL_MAX_ITR); 16951031d839SEric Joyner device_printf(dev, "Using default value of %d instead\n", 16961031d839SEric Joyner IXL_ITR_4K); 16971031d839SEric Joyner pf->tx_itr = IXL_ITR_4K; 16981031d839SEric Joyner } else 16991031d839SEric Joyner pf->tx_itr = ixl_tx_itr; 17001031d839SEric Joyner 17011031d839SEric Joyner if (ixl_rx_itr < 0 || ixl_rx_itr > IXL_MAX_ITR) { 17021031d839SEric Joyner device_printf(dev, "Invalid rx_itr value of %d set!\n", 17031031d839SEric Joyner ixl_rx_itr); 17041031d839SEric Joyner device_printf(dev, "rx_itr must be between %d and %d, " 17051031d839SEric Joyner "inclusive\n", 17061031d839SEric Joyner 0, IXL_MAX_ITR); 17071031d839SEric Joyner device_printf(dev, "Using default value of %d instead\n", 17081031d839SEric Joyner IXL_ITR_8K); 17091031d839SEric Joyner pf->rx_itr = IXL_ITR_8K; 17101031d839SEric Joyner } else 17111031d839SEric Joyner pf->rx_itr = ixl_rx_itr; 17121031d839SEric Joyner } 17131031d839SEric Joyner 1714