Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixgbe/if_ixv.c
| /****************************************************************************** | /****************************************************************************** | ||||
| Copyright (c) 2001-2015, Intel Corporation | Copyright (c) 2001-2017, Intel Corporation | ||||
| All rights reserved. | All rights reserved. | ||||
| Redistribution and use in source and binary forms, with or without | Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | modification, are permitted provided that the following conditions are met: | ||||
| 1. Redistributions of source code must retain the above copyright notice, | 1. Redistributions of source code must retain the above copyright notice, | ||||
| this list of conditions and the following disclaimer. | this list of conditions and the following disclaimer. | ||||
| 2. Redistributions in binary form must reproduce the above copyright | 2. Redistributions in binary form must reproduce the above copyright | ||||
| notice, this list of conditions and the following disclaimer in the | notice, this list of conditions and the following disclaimer in the | ||||
| documentation and/or other materials provided with the distribution. | documentation and/or other materials provided with the distribution. | ||||
| 3. Neither the name of the Intel Corporation nor the names of its | 3. Neither the name of the Intel Corporation nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | this software without specific prior written permission. | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | ||||
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||||
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||||
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGE. | POSSIBILITY OF SUCH DAMAGE. | ||||
| ******************************************************************************/ | ******************************************************************************/ | ||||
| /*$FreeBSD$*/ | /*$FreeBSD$*/ | ||||
| #ifndef IXGBE_STANDALONE_BUILD | |||||
| #include "opt_inet.h" | #include "opt_inet.h" | ||||
| #include "opt_inet6.h" | #include "opt_inet6.h" | ||||
| #endif | |||||
| #include "ixgbe.h" | #include "ixgbe.h" | ||||
| #include "ifdi_if.h" | |||||
| #include <net/netmap.h> | |||||
| #include <dev/netmap/netmap_kern.h> | |||||
| /********************************************************************* | /********************************************************************* | ||||
| * Driver version | * Driver version | ||||
| *********************************************************************/ | *********************************************************************/ | ||||
| char ixv_driver_version[] = "1.4.6-k"; | char ixv_driver_version[] = "1.5.13-k"; | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * PCI Device ID Table | * PCI Device ID Table | ||||
| * | * | ||||
| * Used by probe to select devices to load on | * Used by probe to select devices to load on | ||||
| * Last field stores an index into ixv_strings | * Last field stores an index into ixv_strings | ||||
| * Last entry must be all 0s | * Last entry must be all 0s | ||||
| * | * | ||||
| * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } | * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } | ||||
| *********************************************************************/ | *********************************************************************/ | ||||
| static ixgbe_vendor_info_t ixv_vendor_info_array[] = | static pci_vendor_info_t ixv_vendor_info_array[] = | ||||
| { | { | ||||
| {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_VF, 0, 0, 0}, | PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_VF, "Intel(R) PRO/10GbE Virtual Function Network Driver"), | ||||
| {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_VF, 0, 0, 0}, | PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_VF, "Intel(R) PRO/10GbE Virtual Function Network Driver"), | ||||
| {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550_VF, 0, 0, 0}, | PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550_VF, "Intel(R) PRO/10GbE Virtual Function Network Driver"), | ||||
| {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_VF, 0, 0, 0}, | PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_VF, "Intel(R) PRO/10GbE Virtual Function Network Driver"), | ||||
| PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_VF, "Intel(R) PRO/10GbE Virtual Function Network Driver"), | |||||
| /* required last entry */ | /* required last entry */ | ||||
| {0, 0, 0, 0, 0} | PVID_END | ||||
| }; | }; | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * Table of branding strings | * Function prototypes | ||||
| *********************************************************************/ | *********************************************************************/ | ||||
| static void *ixv_register(device_t dev); | |||||
| static int ixv_if_attach_pre(if_ctx_t ctx); | |||||
| static int ixv_if_attach_post(if_ctx_t ctx); | |||||
| static int ixv_if_detach(if_ctx_t ctx); | |||||
| static char *ixv_strings[] = { | static int ixv_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid); | ||||
| "Intel(R) PRO/10GbE Virtual Function Network Driver" | static int ixv_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nqs, int nqsets); | ||||
| }; | static int ixv_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nqs, int nqsets); | ||||
| static void ixv_if_queues_free(if_ctx_t ctx); | |||||
| static void ixv_identify_hardware(if_ctx_t ctx); | |||||
| static void ixv_init_device_features(struct adapter *); | |||||
| static int ixv_allocate_pci_resources(if_ctx_t ctx); | |||||
| static void ixv_free_pci_resources(if_ctx_t ctx); | |||||
| static int ixv_setup_interface(if_ctx_t ctx); | |||||
| static void ixv_if_media_status(if_ctx_t , struct ifmediareq *); | |||||
| static int ixv_if_media_change(if_ctx_t ctx); | |||||
| static void ixv_if_update_admin_status(if_ctx_t ctx); | |||||
| static int ixv_if_msix_intr_assign(if_ctx_t ctx, int msix); | |||||
| /********************************************************************* | static int ixv_if_mtu_set(if_ctx_t ctx, uint32_t mtu); | ||||
| * Function prototypes | static void ixv_if_init(if_ctx_t ctx); | ||||
| *********************************************************************/ | static void ixv_if_local_timer(if_ctx_t ctx, uint16_t qid); | ||||
| static int ixv_probe(device_t); | static void ixv_if_stop(if_ctx_t ctx); | ||||
| static int ixv_attach(device_t); | |||||
| static int ixv_detach(device_t); | |||||
| static int ixv_shutdown(device_t); | |||||
| static int ixv_ioctl(struct ifnet *, u_long, caddr_t); | |||||
| static void ixv_init(void *); | |||||
| static void ixv_init_locked(struct adapter *); | |||||
| static void ixv_stop(void *); | |||||
| static void ixv_media_status(struct ifnet *, struct ifmediareq *); | |||||
| static int ixv_media_change(struct ifnet *); | |||||
| static void ixv_identify_hardware(struct adapter *); | |||||
| static int ixv_allocate_pci_resources(struct adapter *); | |||||
| static int ixv_allocate_msix(struct adapter *); | |||||
| static int ixv_setup_msix(struct adapter *); | |||||
| static void ixv_free_pci_resources(struct adapter *); | |||||
| static void ixv_local_timer(void *); | |||||
| static void ixv_setup_interface(device_t, struct adapter *); | |||||
| static void ixv_config_link(struct adapter *); | |||||
| static void ixv_initialize_transmit_units(struct adapter *); | static void ixv_initialize_transmit_units(if_ctx_t ctx); | ||||
| static void ixv_initialize_receive_units(struct adapter *); | static void ixv_initialize_receive_units(if_ctx_t ctx); | ||||
| static void ixv_initialize_rss_mapping(struct adapter *); | |||||
| static void ixv_enable_intr(struct adapter *); | static void ixv_setup_vlan_support(if_ctx_t ctx); | ||||
| static void ixv_disable_intr(struct adapter *); | |||||
| static void ixv_set_multi(struct adapter *); | |||||
| static void ixv_update_link_status(struct adapter *); | |||||
| static int ixv_sysctl_debug(SYSCTL_HANDLER_ARGS); | |||||
| static void ixv_set_ivar(struct adapter *, u8, u8, s8); | |||||
| static void ixv_configure_ivars(struct adapter *); | static void ixv_configure_ivars(struct adapter *); | ||||
| static u8 * ixv_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); | static void ixv_if_enable_intr(if_ctx_t ctx); | ||||
| static void ixv_if_disable_intr(if_ctx_t ctx); | |||||
| static void ixv_if_multi_set(if_ctx_t ctx); | |||||
| static void ixv_setup_vlan_support(struct adapter *); | static void ixv_if_register_vlan(if_ctx_t, u16); | ||||
| static void ixv_register_vlan(void *, struct ifnet *, u16); | static void ixv_if_unregister_vlan(if_ctx_t, u16); | ||||
| static void ixv_unregister_vlan(void *, struct ifnet *, u16); | |||||
| static uint64_t ixv_if_get_counter(if_ctx_t, ift_counter); | |||||
| static void ixv_save_stats(struct adapter *); | static void ixv_save_stats(struct adapter *); | ||||
| static void ixv_init_stats(struct adapter *); | static void ixv_init_stats(struct adapter *); | ||||
| static void ixv_update_stats(struct adapter *); | static void ixv_update_stats(struct adapter *); | ||||
| static void ixv_add_stats_sysctls(struct adapter *); | static void ixv_add_stats_sysctls(struct adapter *adapter); | ||||
| static int ixv_sysctl_debug(SYSCTL_HANDLER_ARGS); | |||||
| static void ixv_set_ivar(struct adapter *, u8, u8, s8); | |||||
| static u8 * ixv_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); | |||||
| static void ixv_set_sysctl_value(struct adapter *, const char *, | static void ixv_set_sysctl_value(struct adapter *, const char *, | ||||
| const char *, int *, int); | const char *, int *, int); | ||||
| /* The MSI/X Interrupt handlers */ | /* The MSI/X Interrupt handlers */ | ||||
| static void ixv_msix_que(void *); | static int ixv_msix_que(void *); | ||||
| static void ixv_msix_mbx(void *); | static int ixv_msix_mbx(void *); | ||||
| /* Deferred interrupt tasklets */ | |||||
| static void ixv_handle_que(void *, int); | |||||
| static void ixv_handle_mbx(void *, int); | |||||
| #ifdef DEV_NETMAP | |||||
| /* | |||||
| * This is defined in <dev/netmap/ixgbe_netmap.h>, which is included by | |||||
| * if_ix.c. | |||||
| */ | |||||
| extern void ixgbe_netmap_attach(struct adapter *adapter); | |||||
| #include <net/netmap.h> | |||||
| #include <sys/selinfo.h> | |||||
| #include <dev/netmap/netmap_kern.h> | |||||
| #endif /* DEV_NETMAP */ | |||||
| /********************************************************************* | /********************************************************************* | ||||
| * FreeBSD Device Interface Entry Points | * FreeBSD Device Interface Entry Points | ||||
| *********************************************************************/ | *********************************************************************/ | ||||
| static device_method_t ixv_methods[] = { | static device_method_t ixv_methods[] = { | ||||
| /* Device interface */ | /* Device interface */ | ||||
| DEVMETHOD(device_probe, ixv_probe), | DEVMETHOD(device_register, ixv_register), | ||||
| DEVMETHOD(device_attach, ixv_attach), | DEVMETHOD(device_probe, iflib_device_probe), | ||||
| DEVMETHOD(device_detach, ixv_detach), | DEVMETHOD(device_attach, iflib_device_attach), | ||||
| DEVMETHOD(device_shutdown, ixv_shutdown), | DEVMETHOD(device_detach, iflib_device_detach), | ||||
| DEVMETHOD(device_shutdown, iflib_device_shutdown), | |||||
| DEVMETHOD_END | DEVMETHOD_END | ||||
| }; | }; | ||||
| static driver_t ixv_driver = { | static driver_t ixv_driver = { | ||||
| "ixv", ixv_methods, sizeof(struct adapter), | "ixv", ixv_methods, sizeof(struct adapter), | ||||
| }; | }; | ||||
| devclass_t ixv_devclass; | devclass_t ixv_devclass; | ||||
| DRIVER_MODULE(ixv, pci, ixv_driver, ixv_devclass, 0, 0); | DRIVER_MODULE(ixv, pci, ixv_driver, ixv_devclass, 0, 0); | ||||
| MODULE_DEPEND(ixv, pci, 1, 1, 1); | MODULE_DEPEND(ixv, pci, 1, 1, 1); | ||||
| MODULE_DEPEND(ixv, ether, 1, 1, 1); | MODULE_DEPEND(ixv, ether, 1, 1, 1); | ||||
| #ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
| MODULE_DEPEND(ix, netmap, 1, 1, 1); | MODULE_DEPEND(ix, netmap, 1, 1, 1); | ||||
| #endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
| /* XXX depend on 'ix' ? */ | /* XXX depend on 'ix' ? */ | ||||
| static device_method_t ixv_if_methods[] = { | |||||
| DEVMETHOD(ifdi_attach_pre, ixv_if_attach_pre), | |||||
| DEVMETHOD(ifdi_attach_post, ixv_if_attach_post), | |||||
| DEVMETHOD(ifdi_detach, ixv_if_detach), | |||||
| DEVMETHOD(ifdi_init, ixv_if_init), | |||||
| DEVMETHOD(ifdi_stop, ixv_if_stop), | |||||
| DEVMETHOD(ifdi_msix_intr_assign, ixv_if_msix_intr_assign), | |||||
| DEVMETHOD(ifdi_intr_enable, ixv_if_enable_intr), | |||||
| DEVMETHOD(ifdi_intr_disable, ixv_if_disable_intr), | |||||
| DEVMETHOD(ifdi_tx_queue_intr_enable, ixv_if_rx_queue_intr_enable), | |||||
| DEVMETHOD(ifdi_rx_queue_intr_enable, ixv_if_rx_queue_intr_enable), | |||||
| DEVMETHOD(ifdi_tx_queues_alloc, ixv_if_tx_queues_alloc), | |||||
| DEVMETHOD(ifdi_rx_queues_alloc, ixv_if_rx_queues_alloc), | |||||
| DEVMETHOD(ifdi_queues_free, ixv_if_queues_free), | |||||
| DEVMETHOD(ifdi_update_admin_status, ixv_if_update_admin_status), | |||||
| DEVMETHOD(ifdi_multi_set, ixv_if_multi_set), | |||||
| DEVMETHOD(ifdi_mtu_set, ixv_if_mtu_set), | |||||
| DEVMETHOD(ifdi_media_status, ixv_if_media_status), | |||||
| DEVMETHOD(ifdi_media_change, ixv_if_media_change), | |||||
| DEVMETHOD(ifdi_timer, ixv_if_local_timer), | |||||
| DEVMETHOD(ifdi_vlan_register, ixv_if_register_vlan), | |||||
| DEVMETHOD(ifdi_vlan_unregister, ixv_if_unregister_vlan), | |||||
| DEVMETHOD(ifdi_get_counter, ixv_if_get_counter), | |||||
| DEVMETHOD_END | |||||
| }; | |||||
| static driver_t ixv_if_driver = { | |||||
| "ixv_if", ixv_if_methods, sizeof(struct adapter) | |||||
| }; | |||||
| /* | /* | ||||
| ** TUNEABLE PARAMETERS: | ** TUNEABLE PARAMETERS: | ||||
| */ | */ | ||||
| /* Number of Queues - do not exceed MSIX vectors - 1 */ | /* Number of Queues - do not exceed MSIX vectors - 1 */ | ||||
| static int ixv_num_queues = 1; | static int ixv_num_queues = 1; | ||||
| TUNABLE_INT("hw.ixv.num_queues", &ixv_num_queues); | TUNABLE_INT("hw.ixv.num_queues", &ixv_num_queues); | ||||
| Show All 40 Lines | |||||
| TUNABLE_INT("hw.ixv.rxd", &ixv_rxd); | TUNABLE_INT("hw.ixv.rxd", &ixv_rxd); | ||||
| /* | /* | ||||
| ** Shadow VFTA table, this is needed because | ** Shadow VFTA table, this is needed because | ||||
| ** the real filter table gets cleared during | ** the real filter table gets cleared during | ||||
| ** a soft reset and we need to repopulate it. | ** a soft reset and we need to repopulate it. | ||||
| */ | */ | ||||
| static u32 ixv_shadow_vfta[IXGBE_VFTA_SIZE]; | static u32 ixv_shadow_vfta[IXGBE_VFTA_SIZE]; | ||||
| extern struct if_txrx ixgbe_txrx; | |||||
| /********************************************************************* | static struct if_shared_ctx ixv_sctx_init = { | ||||
| * Device identification routine | .isc_magic = IFLIB_MAGIC, | ||||
| * | .isc_q_align = PAGE_SIZE,/* max(DBA_ALIGN, PAGE_SIZE) */ | ||||
| * ixv_probe determines if the driver should be loaded on | .isc_tx_maxsize = IXGBE_TSO_SIZE, | ||||
| * adapter based on PCI vendor/device id of the adapter. | |||||
| * | |||||
| * return BUS_PROBE_DEFAULT on success, positive on failure | |||||
| *********************************************************************/ | |||||
| .isc_tx_maxsegsize = PAGE_SIZE, | |||||
| .isc_rx_maxsize = MJUM16BYTES, | |||||
| .isc_rx_nsegments = 1, | |||||
| .isc_rx_maxsegsize = MJUM16BYTES, | |||||
| .isc_nfl = 1, | |||||
| .isc_ntxqs = 1, | |||||
| .isc_nrxqs = 1, | |||||
| .isc_admin_intrcnt = 1, | |||||
| .isc_vendor_info = ixv_vendor_info_array, | |||||
| .isc_driver_version = ixv_driver_version, | |||||
| .isc_driver = &ixv_if_driver, | |||||
| .isc_nrxd_min = {MIN_RXD}, | |||||
| .isc_ntxd_min = {MIN_TXD}, | |||||
| .isc_nrxd_max = {MAX_RXD}, | |||||
| .isc_ntxd_max = {MAX_TXD}, | |||||
| .isc_nrxd_default = {DEFAULT_RXD}, | |||||
| .isc_ntxd_default = {DEFAULT_TXD}, | |||||
| }; | |||||
| if_shared_ctx_t ixv_sctx = &ixv_sctx_init; | |||||
| static void * | |||||
| ixv_register(device_t dev) | |||||
| { | |||||
| return (ixv_sctx); | |||||
| } | |||||
| static int | static int | ||||
| ixv_probe(device_t dev) | ixv_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int ntxqs, int ntxqsets) | ||||
| { | { | ||||
| ixgbe_vendor_info_t *ent; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| if_softc_ctx_t scctx = adapter->shared; | |||||
| struct ix_tx_queue *que; | |||||
| int i, j, error; | |||||
| u16 pci_vendor_id = 0; | MPASS(adapter->num_tx_queues == ntxqsets); | ||||
| u16 pci_device_id = 0; | MPASS(ntxqs == 1); | ||||
| u16 pci_subvendor_id = 0; | |||||
| u16 pci_subdevice_id = 0; | |||||
| char adapter_name[256]; | |||||
| /* Allocate queue structure memory */ | |||||
| adapter->tx_queues = | |||||
| (struct ix_tx_queue *)malloc(sizeof(struct ix_tx_queue) * ntxqsets, | |||||
| M_DEVBUF, M_NOWAIT | M_ZERO); | |||||
| if (!adapter->tx_queues) { | |||||
smhUnsubmitted Not Done Inline Actionssmh: == NULL | |||||
| device_printf(iflib_get_dev(ctx), | |||||
| "Unable to allocate TX ring memory\n"); | |||||
| return (ENOMEM); | |||||
| } | |||||
| pci_vendor_id = pci_get_vendor(dev); | for (i = 0, que = adapter->tx_queues; i < ntxqsets; i++, que++) { | ||||
| if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) | struct tx_ring *txr = &que->txr; | ||||
| return (ENXIO); | |||||
| pci_device_id = pci_get_device(dev); | txr->me = i; | ||||
| pci_subvendor_id = pci_get_subvendor(dev); | txr->adapter = que->adapter = adapter; | ||||
| pci_subdevice_id = pci_get_subdevice(dev); | adapter->active_queues |= (u64)1 << txr->me; | ||||
| ent = ixv_vendor_info_array; | /* Allocate report status array */ | ||||
| while (ent->vendor_id != 0) { | if (!(txr->tx_rsq = (qidx_t *)malloc(sizeof(qidx_t) * scctx->isc_ntxd[0], M_DEVBUF, M_NOWAIT | M_ZERO))) { | ||||
| if ((pci_vendor_id == ent->vendor_id) && | error = ENOMEM; | ||||
| (pci_device_id == ent->device_id) && | goto fail; | ||||
| } | |||||
| for (j = 0; j < scctx->isc_ntxd[0]; j++) | |||||
Not Done Inline ActionsLong line smh: Long line | |||||
| txr->tx_rsq[j] = QIDX_INVALID; | |||||
| /* get the virtual and physical address of the hardware queues */ | |||||
| txr->tail = IXGBE_VFTDT(txr->me); | |||||
| txr->tx_base = (union ixgbe_adv_tx_desc *)vaddrs[i*ntxqs]; | |||||
| txr->tx_paddr = paddrs[i*ntxqs]; | |||||
| ((pci_subvendor_id == ent->subvendor_id) || | txr->bytes = 0; | ||||
| (ent->subvendor_id == 0)) && | txr->total_packets = 0; | ||||
| ((pci_subdevice_id == ent->subdevice_id) || | |||||
| (ent->subdevice_id == 0))) { | |||||
| sprintf(adapter_name, "%s, Version - %s", | |||||
| ixv_strings[ent->index], | |||||
| ixv_driver_version); | |||||
| device_set_desc_copy(dev, adapter_name); | |||||
| return (BUS_PROBE_DEFAULT); | |||||
| } | } | ||||
| ent++; | |||||
| device_printf(iflib_get_dev(ctx), "allocated for %d queues\n", | |||||
| adapter->num_tx_queues); | |||||
| return (0); | |||||
| fail: | |||||
| ixv_if_queues_free(ctx); | |||||
| return (error); | |||||
| } | } | ||||
| return (ENXIO); | |||||
| static int | |||||
| ixv_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nrxqs, int nrxqsets) | |||||
| { | |||||
| struct adapter *adapter = iflib_get_softc(ctx); | |||||
| struct ix_rx_queue *que; | |||||
| int i, error; | |||||
| MPASS(adapter->num_rx_queues == nrxqsets); | |||||
| MPASS(nrxqs == 1); | |||||
| /* Allocate queue structure memory */ | |||||
| adapter->rx_queues = | |||||
| (struct ix_rx_queue *)malloc(sizeof(struct ix_rx_queue) * nrxqsets, | |||||
| M_DEVBUF, M_NOWAIT | M_ZERO); | |||||
| if (!adapter->rx_queues) { | |||||
| device_printf(iflib_get_dev(ctx), | |||||
| "Unable to allocate TX ring memory\n"); | |||||
| error = ENOMEM; | |||||
| goto fail; | |||||
| } | } | ||||
| for (i = 0, que = adapter->rx_queues; i < nrxqsets; i++, que++) { | |||||
| struct rx_ring *rxr = &que->rxr; | |||||
| rxr->me = i; | |||||
| rxr->adapter = que->adapter = adapter; | |||||
| /* get the virtual and physical address of the hardware queues */ | |||||
| rxr->tail = IXGBE_VFRDT(rxr->me); | |||||
| rxr->rx_base = (union ixgbe_adv_rx_desc *)vaddrs[i]; | |||||
| rxr->rx_paddr = paddrs[i*nrxqs]; | |||||
| rxr->bytes = 0; | |||||
| rxr->que = que; | |||||
| } | |||||
| device_printf(iflib_get_dev(ctx), "allocated for %d rx queues\n", adapter->num_rx_queues); | |||||
| return (0); | |||||
| fail: | |||||
| ixv_if_queues_free(ctx); | |||||
| return (error); | |||||
| } | |||||
| static void | |||||
Not Done Inline Actions== NULL smh: == NULL | |||||
| ixv_if_queues_free(if_ctx_t ctx) | |||||
| { | |||||
| struct adapter *adapter = iflib_get_softc(ctx); | |||||
| struct ix_tx_queue *que = adapter->tx_queues; | |||||
| int i; | |||||
| if (que == NULL) | |||||
Not Done Inline Actionsformatting smh: formatting | |||||
| goto free; | |||||
| for (i = 0; i < adapter->num_tx_queues; i++, que++) { | |||||
| struct tx_ring *txr = &que->txr; | |||||
| if (txr->tx_rsq == NULL) | |||||
| break; | |||||
| free(txr->tx_rsq, M_DEVBUF); | |||||
| txr->tx_rsq = NULL; | |||||
| } | |||||
| if (adapter->tx_queues != NULL) | |||||
| free(adapter->tx_queues, M_DEVBUF); | |||||
| free: | |||||
| if (adapter->rx_queues != NULL) | |||||
| free(adapter->rx_queues, M_DEVBUF); | |||||
| adapter->tx_queues = NULL; | |||||
| adapter->rx_queues = NULL; | |||||
| } | |||||
| /********************************************************************* | /********************************************************************* | ||||
| * Device initialization routine | * Device initialization routine | ||||
| * | * | ||||
| * The attach entry point is called when the driver is being loaded. | * The attach entry point is called when the driver is being loaded. | ||||
| * This routine identifies the type of hardware, allocates all resources | * This routine identifies the type of hardware, allocates all resources | ||||
| * and initializes the hardware. | * and initializes the hardware. | ||||
| * | * | ||||
| * return 0 on success, positive on failure | * return 0 on success, positive on failure | ||||
| *********************************************************************/ | *********************************************************************/ | ||||
| static int | static int | ||||
| ixv_attach(device_t dev) | ixv_if_attach_pre(if_ctx_t ctx) | ||||
| { | { | ||||
| device_t dev; | |||||
| struct adapter *adapter; | struct adapter *adapter; | ||||
| if_softc_ctx_t scctx; | |||||
| struct ixgbe_hw *hw; | struct ixgbe_hw *hw; | ||||
| int error = 0; | int error = 0; | ||||
| INIT_DEBUGOUT("ixv_attach: begin"); | INIT_DEBUGOUT("ixv_attach: begin"); | ||||
| /* Allocate, clear, and link in our adapter structure */ | /* Allocate, clear, and link in our adapter structure */ | ||||
| adapter = device_get_softc(dev); | dev = iflib_get_dev(ctx); | ||||
Not Done Inline ActionsI thought the kernel free checked this already? Same above smh: I thought the kernel free checked this already? Same above | |||||
| adapter = iflib_get_softc(ctx); | |||||
| adapter->dev = dev; | adapter->dev = dev; | ||||
Not Done Inline ActionsMove above free. smh: Move above free. | |||||
| adapter->ctx = ctx; | |||||
| adapter->hw.back = adapter; | |||||
| scctx = adapter->shared = iflib_get_softc_ctx(ctx); | |||||
| adapter->media = iflib_get_media(ctx); | |||||
| hw = &adapter->hw; | hw = &adapter->hw; | ||||
| #ifdef DEV_NETMAP | /* Do base PCI setup - map BAR0 */ | ||||
| adapter->init_locked = ixv_init_locked; | if (ixv_allocate_pci_resources(ctx)) { | ||||
Not Done Inline Actionsdoes this return a bool or an int if int != 0 check. smh: does this return a bool or an int if int != 0 check. | |||||
| adapter->stop_locked = ixv_stop; | device_printf(dev, "ixv_allocate_pci_resources() failed!\n"); | ||||
| #endif | error = ENXIO; | ||||
| goto err; | |||||
| } | |||||
| /* Core Lock Init*/ | |||||
| IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); | |||||
| /* SYSCTL APIs */ | /* SYSCTL APIs */ | ||||
| SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | ||||
| SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | ||||
| OID_AUTO, "debug", CTLTYPE_INT | CTLFLAG_RW, | OID_AUTO, "debug", CTLTYPE_INT | CTLFLAG_RW, | ||||
| adapter, 0, ixv_sysctl_debug, "I", "Debug Info"); | adapter, 0, ixv_sysctl_debug, "I", "Debug Info"); | ||||
| SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), | SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), | ||||
| SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | ||||
| OID_AUTO, "enable_aim", CTLFLAG_RW, | OID_AUTO, "enable_aim", CTLFLAG_RW, | ||||
| &ixv_enable_aim, 1, "Interrupt Moderation"); | &ixv_enable_aim, 1, "Interrupt Moderation"); | ||||
| /* Set up the timer callout */ | |||||
| callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); | |||||
| /* Determine hardware revision */ | /* Determine hardware revision */ | ||||
| ixv_identify_hardware(adapter); | ixv_identify_hardware(ctx); | ||||
| ixv_init_device_features(adapter); | |||||
| /* Do base PCI setup - map BAR0 */ | /* Initialize the shared code */ | ||||
| if (ixv_allocate_pci_resources(adapter)) { | error = ixgbe_init_ops_vf(hw); | ||||
| device_printf(dev, "ixv_allocate_pci_resources() failed!\n"); | |||||
| error = ENXIO; | |||||
| goto err_out; | |||||
| } | |||||
| /* Sysctls for limiting the amount of work done in the taskqueues */ | |||||
| ixv_set_sysctl_value(adapter, "rx_processing_limit", | |||||
| "max number of rx packets to process", | |||||
| &adapter->rx_process_limit, ixv_rx_process_limit); | |||||
| ixv_set_sysctl_value(adapter, "tx_processing_limit", | |||||
| "max number of tx packets to process", | |||||
| &adapter->tx_process_limit, ixv_tx_process_limit); | |||||
| /* Do descriptor calc and sanity checks */ | |||||
| if (((ixv_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || | |||||
| ixv_txd < MIN_TXD || ixv_txd > MAX_TXD) { | |||||
| device_printf(dev, "TXD config issue, using default!\n"); | |||||
| adapter->num_tx_desc = DEFAULT_TXD; | |||||
| } else | |||||
| adapter->num_tx_desc = ixv_txd; | |||||
| if (((ixv_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || | |||||
| ixv_rxd < MIN_RXD || ixv_rxd > MAX_RXD) { | |||||
| device_printf(dev, "RXD config issue, using default!\n"); | |||||
| adapter->num_rx_desc = DEFAULT_RXD; | |||||
| } else | |||||
| adapter->num_rx_desc = ixv_rxd; | |||||
| /* Allocate our TX/RX Queues */ | |||||
| if (ixgbe_allocate_queues(adapter)) { | |||||
| device_printf(dev, "ixgbe_allocate_queues() failed!\n"); | |||||
| error = ENOMEM; | |||||
| goto err_out; | |||||
| } | |||||
| /* | |||||
| ** Initialize the shared code: its | |||||
| ** at this point the mac type is set. | |||||
| */ | |||||
| error = ixgbe_init_shared_code(hw); | |||||
| if (error) { | if (error) { | ||||
| device_printf(dev, "ixgbe_init_shared_code() failed!\n"); | device_printf(dev, "ixgbe_init_ops_vf() failed!\n"); | ||||
| error = EIO; | error = EIO; | ||||
| goto err_late; | goto err; | ||||
| } | } | ||||
| /* Setup the mailbox */ | /* Setup the mailbox */ | ||||
| ixgbe_init_mbx_params_vf(hw); | ixgbe_init_mbx_params_vf(hw); | ||||
| /* Reset mbox api to 1.0 */ | |||||
| error = ixgbe_reset_hw(hw); | error = ixgbe_reset_hw(hw); | ||||
| if (error == IXGBE_ERR_RESET_FAILED) | if (error == IXGBE_ERR_RESET_FAILED) | ||||
| device_printf(dev, "ixgbe_reset_hw() failure: Reset Failed!\n"); | device_printf(dev, "ixgbe_reset_hw() failure: Reset Failed!\n"); | ||||
| else if (error) | else if (error) | ||||
| device_printf(dev, "ixgbe_reset_hw() failed with error %d\n", error); | device_printf(dev, | ||||
| "ixgbe_reset_hw() failed with error %d\n", error); | |||||
| if (error) { | if (error) { | ||||
| error = EIO; | error = EIO; | ||||
| goto err_late; | goto err; | ||||
| } | } | ||||
| /* Negotiate mailbox API version */ | |||||
| error = ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_11); | |||||
| if (error) { | |||||
| device_printf(dev, "MBX API 1.1 negotiation failed! Error %d\n", error); | |||||
| error = EIO; | |||||
| goto err_late; | |||||
| } | |||||
| error = ixgbe_init_hw(hw); | error = ixgbe_init_hw(hw); | ||||
| if (error) { | if (error) { | ||||
| device_printf(dev, "ixgbe_init_hw() failed!\n"); | device_printf(dev, "ixgbe_init_hw() failed!\n"); | ||||
| error = EIO; | error = EIO; | ||||
| goto err_late; | goto err; | ||||
| } | } | ||||
| error = ixv_allocate_msix(adapter); | /* Negotiate mailbox API version */ | ||||
| error = ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_12); | |||||
| if (error) { | if (error) { | ||||
| device_printf(dev, "ixv_allocate_msix() failed!\n"); | device_printf(dev, | ||||
| goto err_late; | "MBX API 1.2 negotiation failed! Error %d\n", error); | ||||
| error = EIO; | |||||
| goto err; | |||||
| } | } | ||||
| /* If no mac address was assigned, make a random one */ | /* If no mac address was assigned, make a random one */ | ||||
| if (!ixv_check_ether_addr(hw->mac.addr)) { | if (!ixv_check_ether_addr(hw->mac.addr)) { | ||||
| u8 addr[ETHER_ADDR_LEN]; | u8 addr[ETHER_ADDR_LEN]; | ||||
| arc4rand(&addr, sizeof(addr), 0); | arc4rand(&addr, sizeof(addr), 0); | ||||
| addr[0] &= 0xFE; | addr[0] &= 0xFE; | ||||
| addr[0] |= 0x02; | addr[0] |= 0x02; | ||||
| bcopy(addr, hw->mac.addr, sizeof(addr)); | bcopy(addr, hw->mac.addr, sizeof(addr)); | ||||
| bcopy(addr, hw->mac.perm_addr, sizeof(addr)); | |||||
| } | } | ||||
| /* Setup OS specific network interface */ | /* Most of the iflib initialization... */ | ||||
| ixv_setup_interface(dev, adapter); | |||||
| /* Do the stats setup */ | iflib_set_mac(ctx, hw->mac.addr); | ||||
| ixv_save_stats(adapter); | scctx->isc_txqsizes[0] = | ||||
| ixv_init_stats(adapter); | roundup2(scctx->isc_ntxd[0] * sizeof(union ixgbe_adv_tx_desc) + | ||||
| ixv_add_stats_sysctls(adapter); | sizeof(u32), DBA_ALIGN); | ||||
| scctx->isc_rxqsizes[0] = | |||||
| roundup2(scctx->isc_nrxd[0] * sizeof(union ixgbe_adv_rx_desc), | |||||
| DBA_ALIGN); | |||||
| /* XXX */ | |||||
| scctx->isc_max_txqsets = scctx->isc_max_rxqsets = 2; | |||||
| scctx->isc_tx_csum_flags = CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TSO | CSUM_IP6_TCP | CSUM_IP6_UDP | CSUM_IP6_TSO; | |||||
| scctx->isc_tx_nsegments = IXGBE_82599_SCATTER; | |||||
| scctx->isc_msix_bar = PCIR_BAR(MSIX_82598_BAR); | |||||
| scctx->isc_tx_tso_segments_max = scctx->isc_tx_nsegments; | |||||
| scctx->isc_tx_tso_size_max = IXGBE_TSO_SIZE; | |||||
| scctx->isc_tx_tso_segsize_max = PAGE_SIZE; | |||||
| /* Register for VLAN events */ | scctx->isc_txrx = &ixgbe_txrx; | ||||
| adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | |||||
| ixv_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); | |||||
| adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, | |||||
| ixv_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); | |||||
| #ifdef DEV_NETMAP | /* | ||||
| ixgbe_netmap_attach(adapter); | * Tell the upper layer(s) we support everything the PF | ||||
| #endif /* DEV_NETMAP */ | * driver does except... | ||||
| * hardware stats | |||||
| * VLAN tag filtering | |||||
| * Wake-on-LAN | |||||
| * VLAN MTU (device-specific) | |||||
| */ | |||||
| scctx->isc_capenable = IXGBE_CAPS; | |||||
| scctx->isc_capenable ^= IFCAP_HWSTATS | IFCAP_VLAN_HWFILTER | IFCAP_WOL; | |||||
| if (adapter->feat_en & IXGBE_FEATURE_FRAME_LIMIT) | |||||
| scctx->isc_capenable ^= IFCAP_VLAN_MTU; | |||||
| INIT_DEBUGOUT("ixv_attach: end"); | INIT_DEBUGOUT("ixv_attach: end"); | ||||
| return (0); | return (0); | ||||
| err_late: | err: | ||||
| ixgbe_free_transmit_structures(adapter); | ixv_free_pci_resources(ctx); | ||||
| ixgbe_free_receive_structures(adapter); | |||||
| err_out: | |||||
| ixv_free_pci_resources(adapter); | |||||
| return (error); | return (error); | ||||
| } | } | ||||
| /********************************************************************* | |||||
| * Device removal routine | |||||
| * | |||||
| * The detach entry point is called when the driver is being removed. | |||||
| * This routine stops the adapter and deallocates all the resources | |||||
| * that were allocated for driver operation. | |||||
| * | |||||
| * return 0 on success, positive on failure | |||||
| *********************************************************************/ | |||||
| static int | static int | ||||
| ixv_detach(device_t dev) | ixv_if_attach_post(if_ctx_t ctx) | ||||
| { | { | ||||
| struct adapter *adapter = device_get_softc(dev); | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| struct ix_queue *que = adapter->queues; | device_t dev = iflib_get_dev(ctx); | ||||
| int error = 0; | |||||
| INIT_DEBUGOUT("ixv_detach: begin"); | /* Sysctls for limiting the amount of work done in the taskqueues */ | ||||
| ixv_set_sysctl_value(adapter, "rx_processing_limit", | |||||
| "max number of rx packets to process", | |||||
| &adapter->rx_process_limit, ixv_rx_process_limit); | |||||
| /* Make sure VLANS are not using driver */ | ixv_set_sysctl_value(adapter, "tx_processing_limit", | ||||
| if (adapter->ifp->if_vlantrunk != NULL) { | "max number of tx packets to process", | ||||
| device_printf(dev, "Vlan in use, detach first\n"); | &adapter->tx_process_limit, ixv_tx_process_limit); | ||||
| return (EBUSY); | |||||
| } | |||||
| IXGBE_CORE_LOCK(adapter); | /* Setup OS specific network interface */ | ||||
| ixv_stop(adapter); | error = ixv_setup_interface(ctx); | ||||
| IXGBE_CORE_UNLOCK(adapter); | if (error) { | ||||
| device_printf(dev, "Interface setup failed: %d\n", error); | |||||
| for (int i = 0; i < adapter->num_queues; i++, que++) { | goto end; | ||||
Not Done Inline ActionsGiven end only does return (error); just do that here and then return (0); at the end as that makes it clearer whats happening smh: Given end only does return (error); just do that here and then return (0); at the end as that… | |||||
| if (que->tq) { | |||||
| struct tx_ring *txr = que->txr; | |||||
| taskqueue_drain(que->tq, &txr->txq_task); | |||||
| taskqueue_drain(que->tq, &que->que_task); | |||||
| taskqueue_free(que->tq); | |||||
| } | } | ||||
| } | |||||
| /* Drain the Mailbox(link) queue */ | /* Do the stats setup */ | ||||
| if (adapter->tq) { | ixv_save_stats(adapter); | ||||
| taskqueue_drain(adapter->tq, &adapter->link_task); | ixv_init_stats(adapter); | ||||
| taskqueue_free(adapter->tq); | ixv_add_stats_sysctls(adapter); | ||||
| } | |||||
| /* Unregister VLAN events */ | INIT_DEBUGOUT("ixv_attachpost: end"); | ||||
| if (adapter->vlan_attach != NULL) | |||||
| EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); | |||||
| if (adapter->vlan_detach != NULL) | |||||
| EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); | |||||
| ether_ifdetach(adapter->ifp); | end: | ||||
| callout_drain(&adapter->timer); | return error; | ||||
Not Done Inline Actionsbrace return smh: brace return | |||||
| #ifdef DEV_NETMAP | |||||
| netmap_detach(adapter->ifp); | |||||
| #endif /* DEV_NETMAP */ | |||||
| ixv_free_pci_resources(adapter); | |||||
| bus_generic_detach(dev); | |||||
| if_free(adapter->ifp); | |||||
| ixgbe_free_transmit_structures(adapter); | |||||
| ixgbe_free_receive_structures(adapter); | |||||
| IXGBE_CORE_LOCK_DESTROY(adapter); | |||||
| return (0); | |||||
| } | } | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * Device removal routine | |||||
| * | * | ||||
| * Shutdown entry point | * The detach entry point is called when the driver is being removed. | ||||
| * This routine stops the adapter and deallocates all the resources | |||||
| * that were allocated for driver operation. | |||||
| * | * | ||||
| **********************************************************************/ | * return 0 on success, positive on failure | ||||
| *********************************************************************/ | |||||
| static int | static int | ||||
| ixv_shutdown(device_t dev) | ixv_if_detach(if_ctx_t ctx) | ||||
| { | { | ||||
| struct adapter *adapter = device_get_softc(dev); | INIT_DEBUGOUT("ixv_detach: begin"); | ||||
| IXGBE_CORE_LOCK(adapter); | |||||
| ixv_stop(adapter); | ixv_free_pci_resources(ctx); | ||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| return (0); | return (0); | ||||
| } | } | ||||
| /********************************************************************* | |||||
| * Ioctl entry point | |||||
| * | |||||
| * ixv_ioctl is called when the user wants to configure the | |||||
| * interface. | |||||
| * | |||||
| * return 0 on success, positive on failure | |||||
| **********************************************************************/ | |||||
| static int | static int | ||||
| ixv_ioctl(struct ifnet * ifp, u_long command, caddr_t data) | ixv_if_mtu_set(if_ctx_t ctx, uint32_t mtu) | ||||
| { | { | ||||
| struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| struct ifreq *ifr = (struct ifreq *) data; | struct ifnet *ifp = iflib_get_ifp(ctx); | ||||
| #if defined(INET) || defined(INET6) | |||||
| struct ifaddr *ifa = (struct ifaddr *) data; | |||||
| bool avoid_reset = FALSE; | |||||
| #endif | |||||
| int error = 0; | int error = 0; | ||||
| switch (command) { | |||||
| case SIOCSIFADDR: | |||||
| #ifdef INET | |||||
| if (ifa->ifa_addr->sa_family == AF_INET) | |||||
| avoid_reset = TRUE; | |||||
| #endif | |||||
| #ifdef INET6 | |||||
| if (ifa->ifa_addr->sa_family == AF_INET6) | |||||
| avoid_reset = TRUE; | |||||
| #endif | |||||
| #if defined(INET) || defined(INET6) | |||||
| /* | |||||
| ** Calling init results in link renegotiation, | |||||
| ** so we avoid doing it when possible. | |||||
| */ | |||||
| if (avoid_reset) { | |||||
| ifp->if_flags |= IFF_UP; | |||||
| if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) | |||||
| ixv_init(adapter); | |||||
| if (!(ifp->if_flags & IFF_NOARP)) | |||||
| arp_ifinit(ifp, ifa); | |||||
| } else | |||||
| error = ether_ioctl(ifp, command, data); | |||||
| break; | |||||
| #endif | |||||
| case SIOCSIFMTU: | |||||
| IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); | IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); | ||||
| if (ifr->ifr_mtu > IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR) { | if (mtu > IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR) { | ||||
| error = EINVAL; | error = EINVAL; | ||||
Not Done Inline Actionsreturn (EINVAL); and then return (0); at the end eliminating the else and error var makes the flow clearer smh: return (EINVAL); and then return (0); at the end eliminating the else and error var makes the… | |||||
| } else { | } else { | ||||
| IXGBE_CORE_LOCK(adapter); | ifp->if_mtu = mtu; | ||||
| ifp->if_mtu = ifr->ifr_mtu; | adapter->max_frame_size = ifp->if_mtu + IXGBE_MTU_HDR_VLAN; | ||||
| adapter->max_frame_size = | if (adapter->feat_en & IXGBE_FEATURE_FRAME_LIMIT) | ||||
| ifp->if_mtu + IXGBE_MTU_HDR; | adapter->max_frame_size -= ETHER_VLAN_ENCAP_LEN; | ||||
| if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
| ixv_init_locked(adapter); | |||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| } | } | ||||
| break; | return error; | ||||
| case SIOCSIFFLAGS: | |||||
| IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); | |||||
| IXGBE_CORE_LOCK(adapter); | |||||
| if (ifp->if_flags & IFF_UP) { | |||||
| if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | |||||
| ixv_init_locked(adapter); | |||||
| } else | |||||
| if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
| ixv_stop(adapter); | |||||
| adapter->if_flags = ifp->if_flags; | |||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| break; | |||||
| case SIOCADDMULTI: | |||||
| case SIOCDELMULTI: | |||||
| IOCTL_DEBUGOUT("ioctl: SIOC(ADD|DEL)MULTI"); | |||||
| if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | |||||
| IXGBE_CORE_LOCK(adapter); | |||||
| ixv_disable_intr(adapter); | |||||
| ixv_set_multi(adapter); | |||||
| ixv_enable_intr(adapter); | |||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| } | } | ||||
| break; | |||||
| case SIOCSIFMEDIA: | |||||
| case SIOCGIFMEDIA: | |||||
| IOCTL_DEBUGOUT("ioctl: SIOCxIFMEDIA (Get/Set Interface Media)"); | |||||
| error = ifmedia_ioctl(ifp, ifr, &adapter->media, command); | |||||
| break; | |||||
| case SIOCSIFCAP: | |||||
| { | |||||
| int mask = ifr->ifr_reqcap ^ ifp->if_capenable; | |||||
| IOCTL_DEBUGOUT("ioctl: SIOCSIFCAP (Set Capabilities)"); | |||||
| if (mask & IFCAP_HWCSUM) | |||||
| ifp->if_capenable ^= IFCAP_HWCSUM; | |||||
| if (mask & IFCAP_TSO4) | |||||
| ifp->if_capenable ^= IFCAP_TSO4; | |||||
| if (mask & IFCAP_LRO) | |||||
| ifp->if_capenable ^= IFCAP_LRO; | |||||
| if (mask & IFCAP_VLAN_HWTAGGING) | |||||
| ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; | |||||
| if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | |||||
| IXGBE_CORE_LOCK(adapter); | |||||
| ixv_init_locked(adapter); | |||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| } | |||||
| VLAN_CAPABILITIES(ifp); | |||||
| break; | |||||
| } | |||||
| default: | |||||
| IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); | |||||
| error = ether_ioctl(ifp, command, data); | |||||
| break; | |||||
| } | |||||
| return (error); | |||||
| } | |||||
| /********************************************************************* | /********************************************************************* | ||||
| * Init entry point | * Init entry point | ||||
| * | * | ||||
| * This routine is used in two ways. It is used by the stack as | * This routine is used in two ways. It is used by the stack as | ||||
| * init entry point in network interface structure. It is also used | * init entry point in network interface structure. It is also used | ||||
| * by the driver as a hw/sw initialization routine to get to a | * by the driver as a hw/sw initialization routine to get to a | ||||
| * consistent state. | * consistent state. | ||||
| * | * | ||||
| * return 0 on success, positive on failure | * return 0 on success, positive on failure | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| #define IXGBE_MHADD_MFS_SHIFT 16 | #define IXGBE_MHADD_MFS_SHIFT 16 | ||||
| static void | static void | ||||
| ixv_init_locked(struct adapter *adapter) | ixv_if_init(if_ctx_t ctx) | ||||
| { | { | ||||
| struct ifnet *ifp = adapter->ifp; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| device_t dev = adapter->dev; | struct ifnet *ifp = iflib_get_ifp(ctx); | ||||
| device_t dev = iflib_get_dev(ctx); | |||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| int error = 0; | int error = 0; | ||||
| INIT_DEBUGOUT("ixv_init_locked: begin"); | INIT_DEBUGOUT("ixv_init: begin"); | ||||
| mtx_assert(&adapter->core_mtx, MA_OWNED); | |||||
| hw->adapter_stopped = FALSE; | hw->adapter_stopped = FALSE; | ||||
| ixgbe_stop_adapter(hw); | ixgbe_stop_adapter(hw); | ||||
| callout_stop(&adapter->timer); | |||||
| /* reprogram the RAR[0] in case user changed it. */ | /* reprogram the RAR[0] in case user changed it. */ | ||||
| ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); | ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); | ||||
| /* Get the latest mac address, User can use a LAA */ | /* Get the latest mac address, User can use a LAA */ | ||||
| bcopy(IF_LLADDR(adapter->ifp), hw->mac.addr, | bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); | ||||
| IXGBE_ETH_LENGTH_OF_ADDRESS); | |||||
| ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1); | ixgbe_set_rar(hw, 0, hw->mac.addr, 0, 1); | ||||
| hw->addr_ctrl.rar_used_count = 1; | hw->addr_ctrl.rar_used_count = 1; | ||||
| /* Prepare transmit descriptors and buffers */ | |||||
| if (ixgbe_setup_transmit_structures(adapter)) { | |||||
| device_printf(dev, "Could not setup transmit structures\n"); | |||||
| ixv_stop(adapter); | |||||
| return; | |||||
| } | |||||
| /* Reset VF and renegotiate mailbox API version */ | /* Reset VF and renegotiate mailbox API version */ | ||||
| ixgbe_reset_hw(hw); | ixgbe_reset_hw(hw); | ||||
| error = ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_11); | error = ixgbevf_negotiate_api_version(hw, ixgbe_mbox_api_12); | ||||
| if (error) | if (error) | ||||
| device_printf(dev, "MBX API 1.1 negotiation failed! Error %d\n", error); | device_printf(dev, | ||||
| "MBX API 1.2 negotiation failed! Error %d\n", error); | |||||
| ixv_initialize_transmit_units(adapter); | ixv_initialize_transmit_units(ctx); | ||||
| /* Setup Multicast table */ | /* Setup Multicast table */ | ||||
| ixv_set_multi(adapter); | ixv_if_multi_set(ctx); | ||||
| /* | /* | ||||
| ** Determine the correct mbuf pool | ** Determine the correct mbuf pool | ||||
| ** for doing jumbo/headersplit | ** for doing jumbo/headersplit | ||||
| */ | */ | ||||
| if (ifp->if_mtu > ETHERMTU) | if (ifp->if_mtu > ETHERMTU) | ||||
| adapter->rx_mbuf_sz = MJUMPAGESIZE; | adapter->rx_mbuf_sz = MJUMPAGESIZE; | ||||
| else | else | ||||
| adapter->rx_mbuf_sz = MCLBYTES; | adapter->rx_mbuf_sz = MCLBYTES; | ||||
| /* Prepare receive descriptors and buffers */ | |||||
| if (ixgbe_setup_receive_structures(adapter)) { | |||||
| device_printf(dev, "Could not setup receive structures\n"); | |||||
| ixv_stop(adapter); | |||||
| return; | |||||
| } | |||||
| /* Configure RX settings */ | /* Configure RX settings */ | ||||
| ixv_initialize_receive_units(adapter); | ixv_initialize_receive_units(ctx); | ||||
| /* Set the various hardware offload abilities */ | |||||
| ifp->if_hwassist = 0; | |||||
| if (ifp->if_capenable & IFCAP_TSO4) | |||||
| ifp->if_hwassist |= CSUM_TSO; | |||||
| if (ifp->if_capenable & IFCAP_TXCSUM) { | |||||
| ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | |||||
| #if __FreeBSD_version >= 800000 | |||||
| ifp->if_hwassist |= CSUM_SCTP; | |||||
| #endif | |||||
| } | |||||
| /* Set up VLAN offload and filter */ | /* Set up VLAN offload and filter */ | ||||
| ixv_setup_vlan_support(adapter); | ixv_setup_vlan_support(ctx); | ||||
| /* Set up MSI/X routing */ | /* Set up MSI/X routing */ | ||||
| ixv_configure_ivars(adapter); | ixv_configure_ivars(adapter); | ||||
| /* Set up auto-mask */ | /* Set up auto-mask */ | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VTEIAM, IXGBE_EICS_RTX_QUEUE); | IXGBE_WRITE_REG(hw, IXGBE_VTEIAM, IXGBE_EICS_RTX_QUEUE); | ||||
| /* Set moderation on the Link interrupt */ | /* Set moderation on the Link interrupt */ | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VTEITR(adapter->vector), IXGBE_LINK_ITR); | IXGBE_WRITE_REG(hw, IXGBE_VTEITR(adapter->vector), IXGBE_LINK_ITR); | ||||
| /* Stats init */ | /* Stats init */ | ||||
| ixv_init_stats(adapter); | ixv_init_stats(adapter); | ||||
| /* Config/Enable Link */ | /* Config/Enable Link */ | ||||
| ixv_config_link(adapter); | ixgbe_check_link(hw, &adapter->link_speed, &adapter->link_up, | ||||
| FALSE); | |||||
| /* Start watchdog */ | |||||
| callout_reset(&adapter->timer, hz, ixv_local_timer, adapter); | |||||
| /* And now turn on interrupts */ | /* And now turn on interrupts */ | ||||
| ixv_enable_intr(adapter); | ixv_if_enable_intr(ctx); | ||||
| /* Now inform the stack we're ready */ | |||||
| ifp->if_drv_flags |= IFF_DRV_RUNNING; | |||||
| ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | |||||
| return; | return; | ||||
| } | } | ||||
| static void | |||||
| ixv_init(void *arg) | |||||
| { | |||||
| struct adapter *adapter = arg; | |||||
| IXGBE_CORE_LOCK(adapter); | |||||
| ixv_init_locked(adapter); | |||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| return; | |||||
| } | |||||
| /* | /* | ||||
| ** | * | ||||
| ** MSIX Interrupt Handlers and Tasklets | * MSIX Interrupt Handlers and Tasklets | ||||
| ** | * | ||||
| */ | */ | ||||
| static inline void | static inline void | ||||
| ixv_enable_queue(struct adapter *adapter, u32 vector) | ixv_enable_queue(struct adapter *adapter, u32 vector) | ||||
| { | { | ||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| u32 queue = 1 << vector; | u32 queue = 1 << vector; | ||||
| u32 mask; | u32 mask; | ||||
| mask = (IXGBE_EIMS_RTX_QUEUE & queue); | mask = (IXGBE_EIMS_RTX_QUEUE & queue); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); | IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); | ||||
| } | } | ||||
| static inline void | static inline void | ||||
| ixv_disable_queue(struct adapter *adapter, u32 vector) | ixv_disable_queue(struct adapter *adapter, u32 vector) | ||||
| { | { | ||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| u64 queue = (u64)(1 << vector); | u64 queue = (u64)(1 << vector); | ||||
| u32 mask; | u32 mask; | ||||
| mask = (IXGBE_EIMS_RTX_QUEUE & queue); | mask = (IXGBE_EIMS_RTX_QUEUE & queue); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, mask); | IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, mask); | ||||
| } | } | ||||
| static inline void | |||||
| ixv_rearm_queues(struct adapter *adapter, u64 queues) | |||||
| { | |||||
| u32 mask = (IXGBE_EIMS_RTX_QUEUE & queues); | |||||
| IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEICS, mask); | |||||
| } | |||||
| static void | |||||
| ixv_handle_que(void *context, int pending) | |||||
| { | |||||
| struct ix_queue *que = context; | |||||
| struct adapter *adapter = que->adapter; | |||||
| struct tx_ring *txr = que->txr; | |||||
| struct ifnet *ifp = adapter->ifp; | |||||
| bool more; | |||||
| if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | |||||
| more = ixgbe_rxeof(que); | |||||
| IXGBE_TX_LOCK(txr); | |||||
| ixgbe_txeof(txr); | |||||
| #if __FreeBSD_version >= 800000 | |||||
| if (!drbr_empty(ifp, txr->br)) | |||||
| ixgbe_mq_start_locked(ifp, txr); | |||||
| #else | |||||
| if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) | |||||
| ixgbe_start_locked(txr, ifp); | |||||
| #endif | |||||
| IXGBE_TX_UNLOCK(txr); | |||||
| if (more) { | |||||
| taskqueue_enqueue(que->tq, &que->que_task); | |||||
| return; | |||||
| } | |||||
| } | |||||
| /* Reenable this interrupt */ | |||||
| ixv_enable_queue(adapter, que->msix); | |||||
| return; | |||||
| } | |||||
| /********************************************************************* | /********************************************************************* | ||||
| * | * | ||||
| * MSI Queue Interrupt Service routine | * MSI Queue Interrupt Service routine | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| void | static int | ||||
| ixv_msix_que(void *arg) | ixv_msix_que(void *arg) | ||||
| { | { | ||||
| struct ix_queue *que = arg; | struct ix_rx_queue *que = arg; | ||||
| struct adapter *adapter = que->adapter; | struct adapter *adapter = que->adapter; | ||||
| struct ifnet *ifp = adapter->ifp; | struct rx_ring *rxr = &que->rxr; | ||||
| struct tx_ring *txr = que->txr; | |||||
| struct rx_ring *rxr = que->rxr; | |||||
| bool more; | |||||
| u32 newitr = 0; | u32 newitr = 0; | ||||
| #ifdef notyet | |||||
| struct tx_ring *txr = &que->txr; | |||||
| #endif | |||||
| ixv_disable_queue(adapter, que->msix); | ixv_disable_queue(adapter, que->msix); | ||||
| ++que->irqs; | ++que->irqs; | ||||
| more = ixgbe_rxeof(que); | |||||
| IXGBE_TX_LOCK(txr); | |||||
| ixgbe_txeof(txr); | |||||
| /* | |||||
| ** Make certain that if the stack | |||||
| ** has anything queued the task gets | |||||
| ** scheduled to handle it. | |||||
| */ | |||||
| #ifdef IXGBE_LEGACY_TX | |||||
| if (!IFQ_DRV_IS_EMPTY(&adapter->ifp->if_snd)) | |||||
| ixgbe_start_locked(txr, ifp); | |||||
| #else | |||||
| if (!drbr_empty(adapter->ifp, txr->br)) | |||||
| ixgbe_mq_start_locked(ifp, txr); | |||||
| #endif | |||||
| IXGBE_TX_UNLOCK(txr); | |||||
| /* Do AIM now? */ | /* Do AIM now? */ | ||||
| if (ixv_enable_aim == FALSE) | if (ixv_enable_aim == FALSE) | ||||
| goto no_calc; | goto no_calc; | ||||
| /* | /* | ||||
| ** Do Adaptive Interrupt Moderation: | * Do Adaptive Interrupt Moderation: | ||||
| ** - Write out last calculated setting | * - Write out last calculated setting | ||||
| ** - Calculate based on average size over | * - Calculate based on average size over | ||||
| ** the last interval. | * the last interval. | ||||
| */ | */ | ||||
| if (que->eitr_setting) | if (que->eitr_setting) | ||||
| IXGBE_WRITE_REG(&adapter->hw, | IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEITR(que->msix), | ||||
| IXGBE_VTEITR(que->msix), | |||||
| que->eitr_setting); | que->eitr_setting); | ||||
| que->eitr_setting = 0; | que->eitr_setting = 0; | ||||
| /* Idle, do nothing */ | #ifdef notyet | ||||
| if ((txr->bytes == 0) && (rxr->bytes == 0)) | |||||
| goto no_calc; | |||||
| if ((txr->bytes) && (txr->packets)) | if ((txr->bytes) && (txr->packets)) | ||||
| newitr = txr->bytes/txr->packets; | newitr = txr->bytes/txr->packets; | ||||
| #endif | |||||
| if (rxr->bytes == 0) | |||||
| goto no_calc; | |||||
| if ((rxr->bytes) && (rxr->packets)) | if ((rxr->bytes) && (rxr->packets)) | ||||
| newitr = max(newitr, | newitr = max(newitr, (rxr->bytes / rxr->packets)); | ||||
| (rxr->bytes / rxr->packets)); | |||||
| newitr += 24; /* account for hardware frame, crc */ | newitr += 24; /* account for hardware frame, crc */ | ||||
| /* set an upper boundary */ | /* set an upper boundary */ | ||||
| newitr = min(newitr, 3000); | newitr = min(newitr, 3000); | ||||
| /* Be nice to the mid range */ | /* Be nice to the mid range */ | ||||
| if ((newitr > 300) && (newitr < 1200)) | if ((newitr > 300) && (newitr < 1200)) | ||||
| newitr = (newitr / 3); | newitr = (newitr / 3); | ||||
| else | else | ||||
| newitr = (newitr / 2); | newitr = (newitr / 2); | ||||
| newitr |= newitr << 16; | newitr |= newitr << 16; | ||||
| /* save for next interrupt */ | /* save for next interrupt */ | ||||
| que->eitr_setting = newitr; | que->eitr_setting = newitr; | ||||
| #if 0 | |||||
| /* Reset state */ | /* Reset state */ | ||||
| txr->bytes = 0; | txr->bytes = 0; | ||||
| txr->packets = 0; | txr->packets = 0; | ||||
| #endif | |||||
| rxr->bytes = 0; | rxr->bytes = 0; | ||||
| rxr->packets = 0; | rxr->packets = 0; | ||||
| no_calc: | no_calc: | ||||
| if (more) | return (FILTER_SCHEDULE_THREAD); | ||||
| taskqueue_enqueue(que->tq, &que->que_task); | |||||
| else /* Reenable this interrupt */ | |||||
| ixv_enable_queue(adapter, que->msix); | |||||
| return; | |||||
| } | } | ||||
| static void | static int | ||||
| ixv_msix_mbx(void *arg) | ixv_msix_mbx(void *arg) | ||||
| { | { | ||||
| struct adapter *adapter = arg; | struct adapter *adapter = arg; | ||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| u32 reg; | u32 reg; | ||||
| ++adapter->link_irq; | ++adapter->link_irq; | ||||
| /* First get the cause */ | /* First get the cause */ | ||||
| reg = IXGBE_READ_REG(hw, IXGBE_VTEICS); | reg = IXGBE_READ_REG(hw, IXGBE_VTEICS); | ||||
| /* Clear interrupt with write */ | /* Clear interrupt with write */ | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VTEICR, reg); | IXGBE_WRITE_REG(hw, IXGBE_VTEICR, reg); | ||||
| /* Link status change */ | /* Link status change */ | ||||
| if (reg & IXGBE_EICR_LSC) | if (reg & IXGBE_EICR_LSC) | ||||
| taskqueue_enqueue(adapter->tq, &adapter->link_task); | iflib_admin_intr_deferred(adapter->ctx); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, IXGBE_EIMS_OTHER); | IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, IXGBE_EIMS_OTHER); | ||||
| return; | |||||
| return (FILTER_HANDLED); | |||||
| } | } | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * | * | ||||
| * Media Ioctl callback | * Media Ioctl callback | ||||
| * | * | ||||
| * This routine is called whenever the user queries the status of | * This routine is called whenever the user queries the status of | ||||
| * the interface using ifconfig. | * the interface using ifconfig. | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| static void | static void | ||||
| ixv_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) | ixv_if_media_status(if_ctx_t ctx, struct ifmediareq * ifmr) | ||||
| { | { | ||||
| struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| INIT_DEBUGOUT("ixv_media_status: begin"); | INIT_DEBUGOUT("ixv_media_status: begin"); | ||||
| IXGBE_CORE_LOCK(adapter); | ixv_if_update_admin_status(ctx); | ||||
| ixv_update_link_status(adapter); | |||||
| ifmr->ifm_status = IFM_AVALID; | ifmr->ifm_status = IFM_AVALID; | ||||
| ifmr->ifm_active = IFM_ETHER; | ifmr->ifm_active = IFM_ETHER; | ||||
| if (!adapter->link_active) { | if (!adapter->link_active) | ||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| return; | return; | ||||
| } | |||||
| ifmr->ifm_status |= IFM_ACTIVE; | ifmr->ifm_status |= IFM_ACTIVE; | ||||
| switch (adapter->link_speed) { | switch (adapter->link_speed) { | ||||
| case IXGBE_LINK_SPEED_1GB_FULL: | case IXGBE_LINK_SPEED_1GB_FULL: | ||||
Not Done Inline ActionsIndentation smh: Indentation | |||||
| ifmr->ifm_active |= IFM_1000_T | IFM_FDX; | ifmr->ifm_active |= IFM_1000_T | IFM_FDX; | ||||
| break; | break; | ||||
| case IXGBE_LINK_SPEED_10GB_FULL: | case IXGBE_LINK_SPEED_10GB_FULL: | ||||
| ifmr->ifm_active |= IFM_FDX; | ifmr->ifm_active |= IFM_10G_T | IFM_FDX; | ||||
| break; | break; | ||||
| case IXGBE_LINK_SPEED_100_FULL: | |||||
| ifmr->ifm_active |= IFM_100_TX | IFM_FDX; | |||||
| break; | |||||
| case IXGBE_LINK_SPEED_10_FULL: | |||||
| ifmr->ifm_active |= IFM_10_T | IFM_FDX; | |||||
| break; | |||||
| } | } | ||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| return; | return; | ||||
| } | } | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * | * | ||||
| * Media Ioctl callback | * Media Ioctl callback | ||||
| * | * | ||||
| * This routine is called when the user changes speed/duplex using | * This routine is called when the user changes speed/duplex using | ||||
| * media/mediopt option with ifconfig. | * media/mediopt option with ifconfig. | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| static int | static int | ||||
| ixv_media_change(struct ifnet * ifp) | ixv_if_media_change(if_ctx_t ctx) | ||||
| { | { | ||||
| struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| struct ifmedia *ifm = &adapter->media; | struct ifmedia *ifm = iflib_get_media(ctx); | ||||
| INIT_DEBUGOUT("ixv_media_change: begin"); | INIT_DEBUGOUT("ixv_media_change: begin"); | ||||
| if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) | if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) | ||||
| return (EINVAL); | return (EINVAL); | ||||
| switch (IFM_SUBTYPE(ifm->ifm_media)) { | switch (IFM_SUBTYPE(ifm->ifm_media)) { | ||||
| case IFM_AUTO: | case IFM_AUTO: | ||||
| break; | break; | ||||
| default: | default: | ||||
| device_printf(adapter->dev, "Only auto media type\n"); | device_printf(adapter->dev, "Only auto media type\n"); | ||||
Not Done Inline ActionsChange to an if and return (0) then followed by the default case to make flow clearer. smh: Change to an if and return (0) then followed by the default case to make flow clearer. | |||||
| return (EINVAL); | return (EINVAL); | ||||
| } | } | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * Multicast Update | * Multicast Update | ||||
| * | * | ||||
| * This routine is called whenever multicast address list is updated. | * This routine is called whenever multicast address list is updated. | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| #define IXGBE_RAR_ENTRIES 16 | #define IXGBE_RAR_ENTRIES 16 | ||||
| static void | static void | ||||
| ixv_set_multi(struct adapter *adapter) | ixv_if_multi_set(if_ctx_t ctx) | ||||
| { | { | ||||
| struct adapter *adapter = iflib_get_softc(ctx); | |||||
| if_t ifp = iflib_get_ifp(ctx); | |||||
| u8 mta[MAX_NUM_MULTICAST_ADDRESSES * IXGBE_ETH_LENGTH_OF_ADDRESS]; | u8 mta[MAX_NUM_MULTICAST_ADDRESSES * IXGBE_ETH_LENGTH_OF_ADDRESS]; | ||||
| u8 *update_ptr; | u8 *update_ptr; | ||||
| struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
| int mcnt = 0; | int mcnt = 0; | ||||
| struct ifnet *ifp = adapter->ifp; | |||||
| IOCTL_DEBUGOUT("ixv_set_multi: begin"); | IOCTL_DEBUGOUT("ixv_if_multi_set: begin"); | ||||
| #if __FreeBSD_version < 800000 | |||||
| IF_ADDR_LOCK(ifp); | |||||
| #else | |||||
| if_maddr_rlock(ifp); | |||||
| #endif | |||||
| TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | ||||
| if (ifma->ifma_addr->sa_family != AF_LINK) | if (ifma->ifma_addr->sa_family != AF_LINK) | ||||
| continue; | continue; | ||||
| bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), | bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), | ||||
| &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS], | &mta[mcnt * IXGBE_ETH_LENGTH_OF_ADDRESS], | ||||
| IXGBE_ETH_LENGTH_OF_ADDRESS); | IXGBE_ETH_LENGTH_OF_ADDRESS); | ||||
| mcnt++; | mcnt++; | ||||
| } | } | ||||
| #if __FreeBSD_version < 800000 | |||||
| IF_ADDR_UNLOCK(ifp); | |||||
| #else | |||||
| if_maddr_runlock(ifp); | |||||
| #endif | |||||
| update_ptr = mta; | update_ptr = mta; | ||||
| ixgbe_update_mc_addr_list(&adapter->hw, | ixgbe_update_mc_addr_list(&adapter->hw, | ||||
| update_ptr, mcnt, ixv_mc_array_itr, TRUE); | update_ptr, mcnt, ixv_mc_array_itr, TRUE); | ||||
| return; | return; | ||||
| } | } | ||||
| /* | /* | ||||
| * This is an iterator function now needed by the multicast | * This is an iterator function now needed by the multicast | ||||
| * shared code. It simply feeds the shared code routine the | * shared code. It simply feeds the shared code routine the | ||||
| * addresses in the array of ixv_set_multi() one by one. | * addresses in the array of ixv_set_multi() one by one. | ||||
| */ | */ | ||||
| static u8 * | static u8 * | ||||
| ixv_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) | ixv_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) | ||||
| { | { | ||||
| u8 *addr = *update_ptr; | u8 *addr = *update_ptr; | ||||
| u8 *newptr; | u8 *newptr; | ||||
| *vmdq = 0; | *vmdq = 0; | ||||
| newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; | newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; | ||||
| *update_ptr = newptr; | *update_ptr = newptr; | ||||
| return addr; | return addr; | ||||
| } | } | ||||
| /********************************************************************* | /************************************************************************ | ||||
| * Timer routine | * Timer routine | ||||
| * | * | ||||
| * This routine checks for link status,updates statistics, | * This routine checks for link status, updates statistics, | ||||
| * and runs the watchdog check. | * and runs the watchdog check. | ||||
| * | * | ||||
| **********************************************************************/ | ************************************************************************/ | ||||
| static void | static void | ||||
| ixv_local_timer(void *arg) | ixv_if_local_timer(if_ctx_t ctx, uint16_t qid) | ||||
| { | { | ||||
| struct adapter *adapter = arg; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| device_t dev = adapter->dev; | |||||
| struct ix_queue *que = adapter->queues; | |||||
| u64 queues = 0; | |||||
| int hung = 0; | |||||
| mtx_assert(&adapter->core_mtx, MA_OWNED); | if (qid != 0) | ||||
| return; | |||||
| ixv_update_link_status(adapter); | adapter->hw.mac.get_link_status = TRUE; | ||||
| ixgbe_check_link(&adapter->hw, &adapter->link_speed, &adapter->link_up, | |||||
| FALSE); | |||||
| ixv_if_update_admin_status(ctx); | |||||
| /* Stats Update */ | /* Stats Update */ | ||||
| ixv_update_stats(adapter); | ixv_update_stats(adapter); | ||||
| /* | /* Fire off the adminq task */ | ||||
| ** Check the TX queues status | iflib_admin_intr_deferred(ctx); | ||||
| ** - mark hung queues so we don't schedule on them | |||||
| ** - watchdog only if all queues show hung | |||||
| */ | |||||
| for (int i = 0; i < adapter->num_queues; i++, que++) { | |||||
| /* Keep track of queues with work for soft irq */ | |||||
| if (que->txr->busy) | |||||
| queues |= ((u64)1 << que->me); | |||||
| /* | |||||
| ** Each time txeof runs without cleaning, but there | |||||
| ** are uncleaned descriptors it increments busy. If | |||||
| ** we get to the MAX we declare it hung. | |||||
| */ | |||||
| if (que->busy == IXGBE_QUEUE_HUNG) { | |||||
| ++hung; | |||||
| /* Mark the queue as inactive */ | |||||
| adapter->active_queues &= ~((u64)1 << que->me); | |||||
| continue; | |||||
| } else { | |||||
| /* Check if we've come back from hung */ | |||||
| if ((adapter->active_queues & ((u64)1 << que->me)) == 0) | |||||
| adapter->active_queues |= ((u64)1 << que->me); | |||||
| } | } | ||||
| if (que->busy >= IXGBE_MAX_TX_BUSY) { | |||||
| device_printf(dev,"Warning queue %d " | |||||
| "appears to be hung!\n", i); | |||||
| que->txr->busy = IXGBE_QUEUE_HUNG; | |||||
| ++hung; | |||||
| } | |||||
| } | /************************************************************************ | ||||
| * ixv_if_update_admin_status - Update OS on link state | |||||
| /* Only truly watchdog if all queues show hung */ | * | ||||
| if (hung == adapter->num_queues) | * Note: Only updates the OS on the cached link state. | ||||
| goto watchdog; | * The real check of the hardware only happens with | ||||
| else if (queues != 0) { /* Force an IRQ on queues with work */ | * a link interrupt. | ||||
| ixv_rearm_queues(adapter, queues); | ************************************************************************/ | ||||
| } | |||||
| callout_reset(&adapter->timer, hz, ixv_local_timer, adapter); | |||||
| return; | |||||
| watchdog: | |||||
| device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); | |||||
| adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | |||||
| adapter->watchdog_events++; | |||||
| ixv_init_locked(adapter); | |||||
| } | |||||
| /* | |||||
| ** Note: this routine updates the OS on the link state | |||||
| ** the real check of the hardware only happens with | |||||
| ** a link interrupt. | |||||
| */ | |||||
| static void | static void | ||||
| ixv_update_link_status(struct adapter *adapter) | ixv_if_update_admin_status(if_ctx_t ctx) | ||||
| { | { | ||||
| struct ifnet *ifp = adapter->ifp; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| device_t dev = adapter->dev; | device_t dev = iflib_get_dev(ctx); | ||||
| if (adapter->link_up){ | if (adapter->link_up) { | ||||
| if (adapter->link_active == FALSE) { | if (adapter->link_active == FALSE) { | ||||
| if (bootverbose) | if (bootverbose) | ||||
| device_printf(dev,"Link is up %d Gbps %s \n", | device_printf(dev, "Link is up %d Gbps %s \n", | ||||
| ((adapter->link_speed == 128)? 10:1), | ((adapter->link_speed == 128) ? 10 : 1), | ||||
| "Full Duplex"); | "Full Duplex"); | ||||
| adapter->link_active = TRUE; | adapter->link_active = TRUE; | ||||
| if_link_state_change(ifp, LINK_STATE_UP); | iflib_link_state_change(ctx, LINK_STATE_UP, | ||||
| IF_Gbps(10)); | |||||
| } | } | ||||
| } else { /* Link down */ | } else { /* Link down */ | ||||
| if (adapter->link_active == TRUE) { | if (adapter->link_active == TRUE) { | ||||
| if (bootverbose) | if (bootverbose) | ||||
| device_printf(dev,"Link is Down\n"); | device_printf(dev, "Link is Down\n"); | ||||
| if_link_state_change(ifp, LINK_STATE_DOWN); | iflib_link_state_change(ctx, LINK_STATE_DOWN, 0); | ||||
| adapter->link_active = FALSE; | adapter->link_active = FALSE; | ||||
| } | } | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * | * | ||||
| * This routine disables all traffic on the adapter by issuing a | * This routine disables all traffic on the adapter by issuing a | ||||
| * global reset on the MAC and deallocates TX/RX buffers. | * global reset on the MAC and deallocates TX/RX buffers. | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| static void | static void | ||||
| ixv_stop(void *arg) | ixv_if_stop(if_ctx_t ctx) | ||||
| { | { | ||||
| struct ifnet *ifp; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| struct adapter *adapter = arg; | |||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| ifp = adapter->ifp; | |||||
| mtx_assert(&adapter->core_mtx, MA_OWNED); | |||||
| INIT_DEBUGOUT("ixv_stop: begin\n"); | INIT_DEBUGOUT("ixv_stop: begin\n"); | ||||
| ixv_disable_intr(adapter); | |||||
| /* Tell the stack that the interface is no longer active */ | ixv_if_disable_intr(ctx); | ||||
| ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | |||||
| ixgbe_reset_hw(hw); | ixgbe_reset_hw(hw); | ||||
| adapter->hw.adapter_stopped = FALSE; | adapter->hw.adapter_stopped = FALSE; | ||||
| ixgbe_stop_adapter(hw); | ixgbe_stop_adapter(hw); | ||||
| callout_stop(&adapter->timer); | |||||
| /* Update the stack */ | |||||
| adapter->link_up = FALSE; | |||||
| ixv_if_update_admin_status(ctx); | |||||
| /* reprogram the RAR[0] in case user changed it. */ | /* reprogram the RAR[0] in case user changed it. */ | ||||
| ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); | ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); | ||||
| return; | return; | ||||
| } | } | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * | * | ||||
| * Determine hardware revision. | * Determine hardware revision. | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| static void | static void | ||||
| ixv_identify_hardware(struct adapter *adapter) | ixv_identify_hardware(if_ctx_t ctx) | ||||
| { | { | ||||
| device_t dev = adapter->dev; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| device_t dev = iflib_get_dev(ctx); | |||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| /* | |||||
| ** Make sure BUSMASTER is set, on a VM under | |||||
| ** KVM it may not be and will break things. | |||||
| */ | |||||
| pci_enable_busmaster(dev); | |||||
| /* Save off the information about this board */ | /* Save off the information about this board */ | ||||
| hw->vendor_id = pci_get_vendor(dev); | hw->vendor_id = pci_get_vendor(dev); | ||||
| hw->device_id = pci_get_device(dev); | hw->device_id = pci_get_device(dev); | ||||
| hw->revision_id = pci_read_config(dev, PCIR_REVID, 1); | hw->revision_id = pci_get_revid(dev); | ||||
| hw->subsystem_vendor_id = | hw->subsystem_vendor_id = pci_get_subvendor(dev); | ||||
| pci_read_config(dev, PCIR_SUBVEND_0, 2); | hw->subsystem_device_id = pci_get_subdevice(dev); | ||||
| hw->subsystem_device_id = | |||||
| pci_read_config(dev, PCIR_SUBDEV_0, 2); | |||||
| /* We need this to determine device-specific things */ | /* We need this to determine device-specific things */ | ||||
| ixgbe_set_mac_type(hw); | ixgbe_set_mac_type(hw); | ||||
| /* Set the right number of segments */ | |||||
| adapter->num_segs = IXGBE_82599_SCATTER; | |||||
| return; | return; | ||||
| } | } | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * | * | ||||
| * Setup MSIX Interrupt resources and handlers | * Setup MSIX Interrupt resources and handlers | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| static int | static int | ||||
| ixv_allocate_msix(struct adapter *adapter) | ixv_if_msix_intr_assign(if_ctx_t ctx, int msix) | ||||
| { | { | ||||
| device_t dev = adapter->dev; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| struct ix_queue *que = adapter->queues; | device_t dev = iflib_get_dev(ctx); | ||||
| struct tx_ring *txr = adapter->tx_rings; | struct ix_rx_queue *rx_que = adapter->rx_queues; | ||||
| struct ix_tx_queue *tx_que; | |||||
| int error, rid, vector = 0; | int error, rid, vector = 0; | ||||
| char buf[16]; | |||||
| for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { | /* Admin Que is vector 0*/ | ||||
| rid = vector + 1; | rid = vector + 1; | ||||
| que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | for (int i = 0; i < adapter->num_rx_queues; i++, vector++, rx_que++) { | ||||
| RF_SHAREABLE | RF_ACTIVE); | rid = vector + 1; | ||||
| if (que->res == NULL) { | |||||
| device_printf(dev,"Unable to allocate" | snprintf(buf, sizeof(buf), "rxq%d", i); | ||||
| " bus resource: que interrupt [%d]\n", vector); | error = iflib_irq_alloc_generic(ctx, &rx_que->que_irq, rid, | ||||
| return (ENXIO); | IFLIB_INTR_RX, ixv_msix_que, rx_que, rx_que->rxr.me, buf); | ||||
| } | |||||
| /* Set the handler function */ | |||||
| error = bus_setup_intr(dev, que->res, | |||||
| INTR_TYPE_NET | INTR_MPSAFE, NULL, | |||||
| ixv_msix_que, que, &que->tag); | |||||
| if (error) { | if (error) { | ||||
| que->res = NULL; | device_printf(iflib_get_dev(ctx), | ||||
| device_printf(dev, "Failed to register QUE handler"); | "Failed to allocate que int %d err: %d", i, error); | ||||
| return (error); | adapter->num_rx_queues = i + 1; | ||||
| goto fail; | |||||
| } | } | ||||
| #if __FreeBSD_version >= 800504 | |||||
| bus_describe_intr(dev, que->res, que->tag, "que %d", i); | rx_que->msix = vector; | ||||
| #endif | adapter->active_queues |= (u64)(1 << rx_que->msix); | ||||
| que->msix = vector; | |||||
| adapter->active_queues |= (u64)(1 << que->msix); | |||||
| /* | |||||
| ** Bind the msix vector, and thus the | |||||
| ** ring to the corresponding cpu. | |||||
| */ | |||||
| if (adapter->num_queues > 1) | |||||
| bus_bind_intr(dev, que->res, i); | |||||
| TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); | |||||
| TASK_INIT(&que->que_task, 0, ixv_handle_que, que); | |||||
| que->tq = taskqueue_create_fast("ixv_que", M_NOWAIT, | |||||
| taskqueue_thread_enqueue, &que->tq); | |||||
| taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", | |||||
| device_get_nameunit(adapter->dev)); | |||||
| } | } | ||||
| /* and Mailbox */ | for (int i = 0; i < adapter->num_tx_queues; i++) { | ||||
| rid = vector + 1; | snprintf(buf, sizeof(buf), "txq%d", i); | ||||
| adapter->res = bus_alloc_resource_any(dev, | tx_que = &adapter->tx_queues[i]; | ||||
| SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); | tx_que->msix = i % adapter->num_rx_queues; | ||||
| if (!adapter->res) { | iflib_softirq_alloc_generic(ctx, rid, IFLIB_INTR_TX, tx_que, | ||||
| device_printf(dev,"Unable to allocate" | tx_que->txr.me, buf); | ||||
| " bus resource: MBX interrupt [%d]\n", rid); | |||||
| return (ENXIO); | |||||
| } | } | ||||
| /* Set the mbx handler function */ | rid = vector + 1; | ||||
| error = bus_setup_intr(dev, adapter->res, | error = iflib_irq_alloc_generic(ctx, &adapter->irq, rid, | ||||
| INTR_TYPE_NET | INTR_MPSAFE, NULL, | IFLIB_INTR_ADMIN, ixv_msix_mbx, adapter, 0, "aq"); | ||||
| ixv_msix_mbx, adapter, &adapter->tag); | |||||
| if (error) { | if (error) { | ||||
| adapter->res = NULL; | device_printf(iflib_get_dev(ctx), | ||||
| device_printf(dev, "Failed to register LINK handler"); | "Failed to register admin handler"); | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| #if __FreeBSD_version >= 800504 | |||||
| bus_describe_intr(dev, adapter->res, adapter->tag, "mbx"); | |||||
| #endif | |||||
| adapter->vector = vector; | adapter->vector = vector; | ||||
| /* Tasklets for Mailbox */ | |||||
| TASK_INIT(&adapter->link_task, 0, ixv_handle_mbx, adapter); | |||||
| adapter->tq = taskqueue_create_fast("ixv_mbx", M_NOWAIT, | |||||
| taskqueue_thread_enqueue, &adapter->tq); | |||||
| taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s mbxq", | |||||
| device_get_nameunit(adapter->dev)); | |||||
| /* | /* | ||||
| ** Due to a broken design QEMU will fail to properly | * Due to a broken design QEMU will fail to properly | ||||
| ** enable the guest for MSIX unless the vectors in | * enable the guest for MSIX unless the vectors in | ||||
| ** the table are all set up, so we must rewrite the | * the table are all set up, so we must rewrite the | ||||
| ** ENABLE in the MSIX control register again at this | * ENABLE in the MSIX control register again at this | ||||
| ** point to cause it to successfully initialize us. | * point to cause it to successfully initialize us. | ||||
| */ | */ | ||||
| if (adapter->hw.mac.type == ixgbe_mac_82599_vf) { | if (adapter->hw.mac.type == ixgbe_mac_82599_vf) { | ||||
| int msix_ctrl; | int msix_ctrl; | ||||
| pci_find_cap(dev, PCIY_MSIX, &rid); | pci_find_cap(dev, PCIY_MSIX, &rid); | ||||
| rid += PCIR_MSIX_CTRL; | rid += PCIR_MSIX_CTRL; | ||||
| msix_ctrl = pci_read_config(dev, rid, 2); | msix_ctrl = pci_read_config(dev, rid, 2); | ||||
| msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; | msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; | ||||
| pci_write_config(dev, rid, msix_ctrl, 2); | pci_write_config(dev, rid, msix_ctrl, 2); | ||||
| } | } | ||||
| return (0); | return (0); | ||||
| } | |||||
| /* | fail: | ||||
| * Setup MSIX resources, note that the VF | iflib_irq_free(ctx, &adapter->irq); | ||||
| * device MUST use MSIX, there is no fallback. | rx_que = adapter->rx_queues; | ||||
| */ | for (int i = 0; i < adapter->num_rx_queues; i++, rx_que++) | ||||
| static int | iflib_irq_free(ctx, &rx_que->que_irq); | ||||
| ixv_setup_msix(struct adapter *adapter) | return (error); | ||||
| { | |||||
| device_t dev = adapter->dev; | |||||
| int rid, want, msgs; | |||||
| /* Must have at least 2 MSIX vectors */ | |||||
| msgs = pci_msix_count(dev); | |||||
| if (msgs < 2) | |||||
| goto out; | |||||
| rid = PCIR_BAR(3); | |||||
| adapter->msix_mem = bus_alloc_resource_any(dev, | |||||
| SYS_RES_MEMORY, &rid, RF_ACTIVE); | |||||
| if (adapter->msix_mem == NULL) { | |||||
| device_printf(adapter->dev, | |||||
| "Unable to map MSIX table \n"); | |||||
| goto out; | |||||
| } | } | ||||
| /* | |||||
| ** Want vectors for the queues, | |||||
| ** plus an additional for mailbox. | |||||
| */ | |||||
| want = adapter->num_queues + 1; | |||||
| if (want > msgs) { | |||||
| want = msgs; | |||||
| adapter->num_queues = msgs - 1; | |||||
| } else | |||||
| msgs = want; | |||||
| if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { | |||||
| device_printf(adapter->dev, | |||||
| "Using MSIX interrupts with %d vectors\n", want); | |||||
| return (want); | |||||
| } | |||||
| /* Release in case alloc was insufficient */ | |||||
| pci_release_msi(dev); | |||||
| out: | |||||
| if (adapter->msix_mem != NULL) { | |||||
| bus_release_resource(dev, SYS_RES_MEMORY, | |||||
| rid, adapter->msix_mem); | |||||
| adapter->msix_mem = NULL; | |||||
| } | |||||
| device_printf(adapter->dev,"MSIX config error\n"); | |||||
| return (ENXIO); | |||||
| } | |||||
| static int | static int | ||||
| ixv_allocate_pci_resources(struct adapter *adapter) | ixv_allocate_pci_resources(if_ctx_t ctx) | ||||
| { | { | ||||
| struct adapter *adapter = iflib_get_softc(ctx); | |||||
| int rid; | int rid; | ||||
| device_t dev = adapter->dev; | device_t dev = iflib_get_dev(ctx); | ||||
| rid = PCIR_BAR(0); | rid = PCIR_BAR(0); | ||||
| adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | ||||
| &rid, RF_ACTIVE); | &rid, RF_ACTIVE); | ||||
| if (!(adapter->pci_mem)) { | if (!(adapter->pci_mem)) { | ||||
| device_printf(dev, "Unable to allocate bus resource: memory\n"); | device_printf(dev, "Unable to allocate bus resource: memory\n"); | ||||
| return (ENXIO); | return (ENXIO); | ||||
| } | } | ||||
| adapter->osdep.mem_bus_space_tag = | adapter->osdep.mem_bus_space_tag = rman_get_bustag(adapter->pci_mem); | ||||
| rman_get_bustag(adapter->pci_mem); | |||||
| adapter->osdep.mem_bus_space_handle = | adapter->osdep.mem_bus_space_handle = | ||||
| rman_get_bushandle(adapter->pci_mem); | rman_get_bushandle(adapter->pci_mem); | ||||
| adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; | adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; | ||||
| /* Pick up the tuneable queues */ | /* Pick up the tuneable queues */ | ||||
| adapter->num_queues = ixv_num_queues; | adapter->num_rx_queues = adapter->num_tx_queues = ixv_num_queues; | ||||
| adapter->hw.back = adapter; | |||||
| /* | |||||
| ** Now setup MSI/X, should | |||||
| ** return us the number of | |||||
| ** configured vectors. | |||||
| */ | |||||
| adapter->msix = ixv_setup_msix(adapter); | |||||
| if (adapter->msix == ENXIO) | |||||
| return (ENXIO); | |||||
| else | |||||
| return (0); | return (0); | ||||
| } | } | ||||
| static void | static void | ||||
| ixv_free_pci_resources(struct adapter * adapter) | ixv_free_pci_resources(if_ctx_t ctx) | ||||
| { | { | ||||
| struct ix_queue *que = adapter->queues; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| device_t dev = adapter->dev; | struct ix_rx_queue *que = adapter->rx_queues; | ||||
| int rid, memrid; | device_t dev = iflib_get_dev(ctx); | ||||
| memrid = PCIR_BAR(MSIX_82598_BAR); | /* Release all msix queue resources */ | ||||
| if (adapter->intr_type == IFLIB_INTR_MSIX) | |||||
| iflib_irq_free(ctx, &adapter->irq); | |||||
| /* | if (que != NULL) { | ||||
| ** There is a slight possibility of a failure mode | for (int i = 0; i < adapter->num_rx_queues; i++, que++) { | ||||
| ** in attach that will result in entering this function | iflib_irq_free(ctx, &que->que_irq); | ||||
| ** before interrupt resources have been initialized, and | |||||
| ** in that case we do not want to execute the loops below | |||||
| ** We can detect this reliably by the state of the adapter | |||||
| ** res pointer. | |||||
| */ | |||||
| if (adapter->res == NULL) | |||||
| goto mem; | |||||
| /* | |||||
| ** Release all msix queue resources: | |||||
| */ | |||||
| for (int i = 0; i < adapter->num_queues; i++, que++) { | |||||
| rid = que->msix + 1; | |||||
| if (que->tag != NULL) { | |||||
| bus_teardown_intr(dev, que->res, que->tag); | |||||
| que->tag = NULL; | |||||
| } | } | ||||
| if (que->res != NULL) | |||||
| bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); | |||||
| } | } | ||||
| /* Clean the Legacy or Link interrupt last */ | /* Clean the Legacy or Link interrupt last */ | ||||
| if (adapter->vector) /* we are doing MSIX */ | |||||
| rid = adapter->vector + 1; | |||||
| else | |||||
| (adapter->msix != 0) ? (rid = 1):(rid = 0); | |||||
| if (adapter->tag != NULL) { | |||||
| bus_teardown_intr(dev, adapter->res, adapter->tag); | |||||
| adapter->tag = NULL; | |||||
| } | |||||
| if (adapter->res != NULL) | |||||
| bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); | |||||
| mem: | |||||
| if (adapter->msix) | |||||
| pci_release_msi(dev); | |||||
| if (adapter->msix_mem != NULL) | |||||
| bus_release_resource(dev, SYS_RES_MEMORY, | |||||
| memrid, adapter->msix_mem); | |||||
| if (adapter->pci_mem != NULL) | if (adapter->pci_mem != NULL) | ||||
| bus_release_resource(dev, SYS_RES_MEMORY, | bus_release_resource(dev, SYS_RES_MEMORY, | ||||
| PCIR_BAR(0), adapter->pci_mem); | PCIR_BAR(0), adapter->pci_mem); | ||||
| return; | return; | ||||
Not Done Inline Actionsno need for return on void func smh: no need for return on void func | |||||
| } | } | ||||
| /********************************************************************* | /********************************************************************* | ||||
| * | * | ||||
| * Setup networking device structure and register an interface. | * Setup networking device structure and register an interface. | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| static void | static int | ||||
| ixv_setup_interface(device_t dev, struct adapter *adapter) | ixv_setup_interface(if_ctx_t ctx) | ||||
| { | { | ||||
| struct ifnet *ifp; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| if_softc_ctx_t scctx = adapter->shared; | |||||
| struct ifnet *ifp = iflib_get_ifp(ctx); | |||||
| INIT_DEBUGOUT("ixv_setup_interface: begin"); | INIT_DEBUGOUT("ixv_setup_interface: begin"); | ||||
| ifp = adapter->ifp = if_alloc(IFT_ETHER); | if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); | ||||
| if (ifp == NULL) | if_setbaudrate(ifp, IF_Gbps(10)); | ||||
| panic("%s: can not if_alloc()\n", device_get_nameunit(dev)); | ifp->if_snd.ifq_maxlen = scctx->isc_ntxd[0] - 2; | ||||
| if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | |||||
| ifp->if_baudrate = 1000000000; | |||||
| ifp->if_init = ixv_init; | |||||
| ifp->if_softc = adapter; | |||||
| ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |||||
| ifp->if_ioctl = ixv_ioctl; | |||||
| #if __FreeBSD_version >= 800000 | |||||
| ifp->if_transmit = ixgbe_mq_start; | |||||
| ifp->if_qflush = ixgbe_qflush; | |||||
| #else | |||||
| ifp->if_start = ixgbe_start; | |||||
| #endif | |||||
| ifp->if_snd.ifq_maxlen = adapter->num_tx_desc - 2; | |||||
| ether_ifattach(ifp, adapter->hw.mac.addr); | adapter->max_frame_size = ifp->if_mtu + IXGBE_MTU_HDR_VLAN; | ||||
| if (adapter->feat_en & IXGBE_FEATURE_FRAME_LIMIT) | |||||
| adapter->max_frame_size -= ETHER_VLAN_ENCAP_LEN; | |||||
| adapter->max_frame_size = | ifmedia_add(adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); | ||||
| ifp->if_mtu + IXGBE_MTU_HDR_VLAN; | ifmedia_set(adapter->media, IFM_ETHER | IFM_AUTO); | ||||
| /* | return 0; | ||||
Not Done Inline Actionsbrace smh: brace | |||||
| * Tell the upper layer(s) we support long frames. | |||||
| */ | |||||
| ifp->if_hdrlen = sizeof(struct ether_vlan_header); | |||||
| ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_TSO4 | IFCAP_VLAN_HWCSUM; | |||||
| ifp->if_capabilities |= IFCAP_JUMBO_MTU; | |||||
| ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | |||||
| | IFCAP_VLAN_HWTSO | |||||
| | IFCAP_VLAN_MTU; | |||||
| ifp->if_capabilities |= IFCAP_LRO; | |||||
| ifp->if_capenable = ifp->if_capabilities; | |||||
| /* | |||||
| * Specify the media types supported by this adapter and register | |||||
| * callbacks to update media and link information | |||||
| */ | |||||
| ifmedia_init(&adapter->media, IFM_IMASK, ixv_media_change, | |||||
| ixv_media_status); | |||||
| ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); | |||||
| ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); | |||||
| return; | |||||
| } | } | ||||
| static void | static uint64_t | ||||
| ixv_config_link(struct adapter *adapter) | ixv_if_get_counter(if_ctx_t ctx, ift_counter cnt) | ||||
| { | { | ||||
| struct ixgbe_hw *hw = &adapter->hw; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| u32 autoneg; | if_t ifp = iflib_get_ifp(ctx); | ||||
| if (hw->mac.ops.check_link) | switch (cnt) { | ||||
| hw->mac.ops.check_link(hw, &autoneg, | case IFCOUNTER_IPACKETS: | ||||
| &adapter->link_up, FALSE); | return (adapter->ipackets); | ||||
| case IFCOUNTER_OPACKETS: | |||||
| return (adapter->opackets); | |||||
| case IFCOUNTER_IBYTES: | |||||
| return (adapter->ibytes); | |||||
| case IFCOUNTER_OBYTES: | |||||
| return (adapter->obytes); | |||||
| case IFCOUNTER_IMCASTS: | |||||
| return (adapter->imcasts); | |||||
| default: | |||||
| return (if_get_counter_default(ifp, cnt)); | |||||
| } | } | ||||
| } | |||||
| /********************************************************************* | /********************************************************************* | ||||
| * | * | ||||
| * Enable transmit unit. | * Enable transmit unit. | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| static void | static void | ||||
| ixv_initialize_transmit_units(struct adapter *adapter) | ixv_initialize_transmit_units(if_ctx_t ctx) | ||||
| { | { | ||||
| struct tx_ring *txr = adapter->tx_rings; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| if_softc_ctx_t scctx = adapter->shared; | |||||
| struct ix_tx_queue *que = adapter->tx_queues; | |||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| int i; | |||||
| for (i = 0; i < adapter->num_tx_queues; i++, que++) { | |||||
| for (int i = 0; i < adapter->num_queues; i++, txr++) { | struct tx_ring *txr = &que->txr; | ||||
| u64 tdba = txr->txdma.dma_paddr; | u64 tdba = txr->tx_paddr; | ||||
| u32 txctrl, txdctl; | u32 txctrl, txdctl; | ||||
| int j = txr->me; | |||||
| /* Set WTHRESH to 8, burst writeback */ | /* Set WTHRESH to 8, burst writeback */ | ||||
| txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i)); | txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j)); | ||||
| txdctl |= (8 << 16); | txdctl |= (8 << 16); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), txdctl); | IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl); | ||||
| /* Set the HW Tx Head and Tail indices */ | /* Set the HW Tx Head and Tail indices */ | ||||
| IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDH(i), 0); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDH(j), 0); | ||||
| IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDT(i), 0); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDT(j), 0); | ||||
| /* Set Tx Tail register */ | /* Set Tx Tail register */ | ||||
| txr->tail = IXGBE_VFTDT(i); | txr->tail = IXGBE_VFTDT(j); | ||||
| txr->tx_rs_cidx = txr->tx_rs_pidx = txr->tx_cidx_processed = 0; | |||||
| for (int k = 0; k < scctx->isc_ntxd[0]; k++) | |||||
| txr->tx_rsq[k] = QIDX_INVALID; | |||||
| /* Set Ring parameters */ | /* Set Ring parameters */ | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFTDBAL(i), | IXGBE_WRITE_REG(hw, IXGBE_VFTDBAL(j), | ||||
| (tdba & 0x00000000ffffffffULL)); | (tdba & 0x00000000ffffffffULL)); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFTDBAH(i), (tdba >> 32)); | IXGBE_WRITE_REG(hw, IXGBE_VFTDBAH(j), (tdba >> 32)); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(i), | IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(j), | ||||
| adapter->num_tx_desc * | scctx->isc_ntxd[0] * sizeof(struct ixgbe_legacy_tx_desc)); | ||||
| sizeof(struct ixgbe_legacy_tx_desc)); | txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j)); | ||||
| txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(i)); | |||||
| txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; | txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(i), txctrl); | IXGBE_WRITE_REG(hw, IXGBE_VFDCA_TXCTRL(j), txctrl); | ||||
| /* Now enable */ | /* Now enable */ | ||||
| txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i)); | txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j)); | ||||
| txdctl |= IXGBE_TXDCTL_ENABLE; | txdctl |= IXGBE_TXDCTL_ENABLE; | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), txdctl); | IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl); | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| /************************************************************************ | |||||
| * ixv_initialize_rss_mapping | |||||
| ************************************************************************/ | |||||
| static void | |||||
| ixv_initialize_rss_mapping(struct adapter *adapter) | |||||
| { | |||||
| struct ixgbe_hw *hw = &adapter->hw; | |||||
| u32 reta = 0, mrqc, rss_key[10]; | |||||
| int queue_id; | |||||
| int i, j; | |||||
| u32 rss_hash_config; | |||||
| if (adapter->feat_en & IXGBE_FEATURE_RSS) { | |||||
| /* Fetch the configured RSS key */ | |||||
| rss_getkey((uint8_t *)&rss_key); | |||||
| } else { | |||||
| /* set up random bits */ | |||||
| arc4rand(&rss_key, sizeof(rss_key), 0); | |||||
| } | |||||
| /* Now fill out hash function seeds */ | |||||
| for (i = 0; i < 10; i++) | |||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]); | |||||
| /* Set up the redirection table */ | |||||
| for (i = 0, j = 0; i < 64; i++, j++) { | |||||
| if (j == adapter->num_rx_queues) | |||||
| j = 0; | |||||
| if (adapter->feat_en & IXGBE_FEATURE_RSS) { | |||||
| /* | |||||
| * Fetch the RSS bucket id for the given indirection | |||||
| * entry. Cap it at the number of configured buckets | |||||
| * (which is num_rx_queues.) | |||||
| */ | |||||
| queue_id = rss_get_indirection_to_bucket(i); | |||||
| queue_id = queue_id % adapter->num_rx_queues; | |||||
| } else | |||||
| queue_id = j; | |||||
| /* | |||||
| * The low 8 bits are for hash value (n+0); | |||||
| * The next 8 bits are for hash value (n+1), etc. | |||||
| */ | |||||
| reta >>= 8; | |||||
| reta |= ((uint32_t)queue_id) << 24; | |||||
| if ((i & 3) == 3) { | |||||
Not Done Inline Actionswhat is the 3, need a constant? smh: what is the 3, need a constant? | |||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRETA(i >> 2), reta); | |||||
| reta = 0; | |||||
| } | |||||
| } | |||||
| /* Perform hash on these packet types */ | |||||
| if (adapter->feat_en & IXGBE_FEATURE_RSS) | |||||
Not Done Inline Actions!= 0 smh: != 0 | |||||
| rss_hash_config = rss_gethashconfig(); | |||||
| else { | |||||
| /* | |||||
| * Disable UDP - IP fragments aren't currently being handled | |||||
| * and so we end up with a mix of 2-tuple and 4-tuple | |||||
| * traffic. | |||||
| */ | |||||
| rss_hash_config = RSS_HASHTYPE_RSS_IPV4 | |||||
| | RSS_HASHTYPE_RSS_TCP_IPV4 | |||||
| | RSS_HASHTYPE_RSS_IPV6 | |||||
| | RSS_HASHTYPE_RSS_TCP_IPV6; | |||||
| } | |||||
| mrqc = IXGBE_MRQC_RSSEN; | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) | |||||
| mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) | |||||
| mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) | |||||
| mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) | |||||
| mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) | |||||
| device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_IPV6_EX defined, but not supported\n", | |||||
| __func__); | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) | |||||
| device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_TCP_IPV6_EX defined, but not supported\n", | |||||
| __func__); | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) | |||||
| mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) | |||||
| device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, but not supported\n", | |||||
| __func__); | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) | |||||
| mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; | |||||
| if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) | |||||
| device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_UDP_IPV6_EX defined, but not supported\n", | |||||
| __func__); | |||||
| IXGBE_WRITE_REG(hw, IXGBE_VFMRQC, mrqc); | |||||
| } /* ixv_initialize_rss_mapping */ | |||||
| /********************************************************************* | /********************************************************************* | ||||
| * | * | ||||
| * Setup receive registers and features. | * Setup receive registers and features. | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 | |||||
| static void | static void | ||||
| ixv_initialize_receive_units(struct adapter *adapter) | ixv_initialize_receive_units(if_ctx_t ctx) | ||||
| { | { | ||||
| struct rx_ring *rxr = adapter->rx_rings; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| if_softc_ctx_t scctx; | |||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = iflib_get_ifp(ctx); | ||||
| struct ix_rx_queue *que = adapter->rx_queues; | |||||
| u32 bufsz, rxcsum, psrtype; | u32 bufsz, rxcsum, psrtype; | ||||
| if (ifp->if_mtu > ETHERMTU) | if (ifp->if_mtu > ETHERMTU) | ||||
| bufsz = 4096 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | bufsz = 4096 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | ||||
| else | else | ||||
| bufsz = 2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | bufsz = 2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | ||||
| psrtype = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | | psrtype = IXGBE_PSRTYPE_TCPHDR | IXGBE_PSRTYPE_UDPHDR | | ||||
| IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR | | IXGBE_PSRTYPE_IPV4HDR | IXGBE_PSRTYPE_IPV6HDR | | ||||
| IXGBE_PSRTYPE_L2HDR; | IXGBE_PSRTYPE_L2HDR; | ||||
| if (adapter->num_rx_queues > 1) | |||||
| psrtype |= 1 << 29; | |||||
| IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype); | IXGBE_WRITE_REG(hw, IXGBE_VFPSRTYPE, psrtype); | ||||
| /* Tell PF our max_frame size */ | /* Tell PF our max_frame size */ | ||||
| ixgbevf_rlpml_set_vf(hw, adapter->max_frame_size); | if (ixgbevf_rlpml_set_vf(hw, adapter->max_frame_size) != 0) { | ||||
| device_printf(adapter->dev, "There is a problem with the PF setup. It is likely the receive unit for this VF will not function correctly.\n"); | |||||
| } | |||||
| scctx = adapter->shared; | |||||
| for (int i = 0; i < adapter->num_queues; i++, rxr++) { | for (int i = 0; i < adapter->num_rx_queues; i++, que++) { | ||||
Not Done Inline Actions!= 0 smh: != 0 | |||||
| u64 rdba = rxr->rxdma.dma_paddr; | struct rx_ring *rxr = &que->rxr; | ||||
Not Done Inline ActionsLong line. smh: Long line. | |||||
| u64 rdba = rxr->rx_paddr; | |||||
| u32 reg, rxdctl; | u32 reg, rxdctl; | ||||
| int j = rxr->me; | |||||
| /* Disable the queue */ | /* Disable the queue */ | ||||
| rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)); | rxdctl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j)); | ||||
Not Done Inline Actions!= 0 or == 1? smh: != 0 or == 1? | |||||
| rxdctl &= ~IXGBE_RXDCTL_ENABLE; | rxdctl &= ~IXGBE_RXDCTL_ENABLE; | ||||
Not Done Inline ActionsLong line smh: Long line | |||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), rxdctl); | IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(j), rxdctl); | ||||
| for (int j = 0; j < 10; j++) { | for (int k = 0; k < 10; k++) { | ||||
| if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)) & | if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j)) & | ||||
| IXGBE_RXDCTL_ENABLE) | IXGBE_RXDCTL_ENABLE) | ||||
| msec_delay(1); | msec_delay(1); | ||||
| else | else | ||||
| break; | break; | ||||
| } | } | ||||
| wmb(); | wmb(); | ||||
| /* Setup the Base and Length of the Rx Descriptor Ring */ | /* Setup the Base and Length of the Rx Descriptor Ring */ | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(i), | IXGBE_WRITE_REG(hw, IXGBE_VFRDBAL(j), | ||||
| (rdba & 0x00000000ffffffffULL)); | (rdba & 0x00000000ffffffffULL)); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(i), | IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(j), (rdba >> 32)); | ||||
| (rdba >> 32)); | IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(j), | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(i), | scctx->isc_nrxd[0] * sizeof(union ixgbe_adv_rx_desc)); | ||||
| adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); | |||||
| /* Reset the ring indices */ | /* Reset the ring indices */ | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRDH(rxr->me), 0); | IXGBE_WRITE_REG(hw, IXGBE_VFRDH(rxr->me), 0); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), 0); | IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), 0); | ||||
| /* Set up the SRRCTL register */ | /* Set up the SRRCTL register */ | ||||
| reg = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(i)); | reg = IXGBE_READ_REG(hw, IXGBE_VFSRRCTL(j)); | ||||
| reg &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; | reg &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; | ||||
| reg &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; | reg &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; | ||||
| reg |= bufsz; | reg |= bufsz; | ||||
| reg |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; | reg |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF; | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(i), reg); | IXGBE_WRITE_REG(hw, IXGBE_VFSRRCTL(j), reg); | ||||
| /* Capture Rx Tail index */ | /* Capture Rx Tail index */ | ||||
| rxr->tail = IXGBE_VFRDT(rxr->me); | rxr->tail = IXGBE_VFRDT(rxr->me); | ||||
| /* Do the queue enabling last */ | /* Do the queue enabling last */ | ||||
| rxdctl |= IXGBE_RXDCTL_ENABLE | IXGBE_RXDCTL_VME; | rxdctl |= IXGBE_RXDCTL_ENABLE | IXGBE_RXDCTL_VME; | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), rxdctl); | IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(j), rxdctl); | ||||
| for (int k = 0; k < 10; k++) { | for (int l = 0; l < 10; l++) { | ||||
| if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)) & | if (IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(j)) & | ||||
| IXGBE_RXDCTL_ENABLE) | IXGBE_RXDCTL_ENABLE) | ||||
| break; | break; | ||||
| else | |||||
| msec_delay(1); | msec_delay(1); | ||||
| } | } | ||||
| wmb(); | wmb(); | ||||
| /* Set the Tail Pointer */ | /* Set the Tail Pointer */ | ||||
| #ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
| /* | /* | ||||
| * In netmap mode, we must preserve the buffers made | * In netmap mode, we must preserve the buffers made | ||||
| * available to userspace before the if_init() | * available to userspace before the if_init() | ||||
| * (this is true by default on the TX side, because | * (this is true by default on the TX side, because | ||||
| * init makes all buffers available to userspace). | * init makes all buffers available to userspace). | ||||
| * | * | ||||
| * netmap_reset() and the device specific routines | * netmap_reset() and the device specific routines | ||||
| * (e.g. ixgbe_setup_receive_rings()) map these | * (e.g. ixgbe_setup_receive_rings()) map these | ||||
| * buffers at the end of the NIC ring, so here we | * buffers at the end of the NIC ring, so here we | ||||
| * must set the RDT (tail) register to make sure | * must set the RDT (tail) register to make sure | ||||
| * they are not overwritten. | * they are not overwritten. | ||||
| * | * | ||||
| * In this driver the NIC ring starts at RDH = 0, | * In this driver the NIC ring starts at RDH = 0, | ||||
| * RDT points to the last slot available for reception (?), | * RDT points to the last slot available for reception (?), | ||||
| * so RDT = num_rx_desc - 1 means the whole ring is available. | * so RDT = num_rx_desc - 1 means the whole ring is available. | ||||
| */ | */ | ||||
| if (ifp->if_capenable & IFCAP_NETMAP) { | if (ifp->if_capenable & IFCAP_NETMAP) { | ||||
| struct netmap_adapter *na = NA(adapter->ifp); | struct netmap_adapter *na = NA(ifp); | ||||
| struct netmap_kring *kring = &na->rx_rings[i]; | struct netmap_kring *kring = &na->rx_rings[j]; | ||||
| int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); | int t = na->num_rx_desc - 1 - nm_kr_rxspace(kring); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), t); | IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), t); | ||||
| } else | } else | ||||
| #endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), | IXGBE_WRITE_REG(hw, IXGBE_VFRDT(rxr->me), | ||||
| adapter->num_rx_desc - 1); | scctx->isc_nrxd[0] - 1); | ||||
| } | } | ||||
| rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); | rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); | ||||
| ixv_initialize_rss_mapping(adapter); | |||||
| if (adapter->num_rx_queues > 1) { | |||||
| /* RSS and RX IPP Checksum are mutually exclusive */ | |||||
| rxcsum |= IXGBE_RXCSUM_PCSD; | |||||
| } | |||||
| if (ifp->if_capenable & IFCAP_RXCSUM) | if (ifp->if_capenable & IFCAP_RXCSUM) | ||||
| rxcsum |= IXGBE_RXCSUM_PCSD; | rxcsum |= IXGBE_RXCSUM_PCSD; | ||||
| if (!(rxcsum & IXGBE_RXCSUM_PCSD)) | if (!(rxcsum & IXGBE_RXCSUM_PCSD)) | ||||
| rxcsum |= IXGBE_RXCSUM_IPPCSE; | rxcsum |= IXGBE_RXCSUM_IPPCSE; | ||||
| IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); | IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); | ||||
| return; | return; | ||||
| } | } | ||||
| static void | static void | ||||
| ixv_setup_vlan_support(struct adapter *adapter) | ixv_setup_vlan_support(if_ctx_t ctx) | ||||
| { | { | ||||
| struct adapter *adapter = iflib_get_softc(ctx); | |||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| u32 ctrl, vid, vfta, retry; | u32 ctrl, vid, vfta, retry; | ||||
| struct rx_ring *rxr; | |||||
| /* | /* | ||||
| ** We get here thru init_locked, meaning | ** We get here thru init_locked, meaning | ||||
| ** a soft reset, this has already cleared | ** a soft reset, this has already cleared | ||||
| ** the VFTA and other state, so if there | ** the VFTA and other state, so if there | ||||
| ** have been no vlan's registered do nothing. | ** have been no vlan's registered do nothing. | ||||
| */ | */ | ||||
| if (adapter->num_vlans == 0) | if (adapter->num_vlans == 0) | ||||
| return; | return; | ||||
| /* Enable the queues */ | /* Enable the queues */ | ||||
| for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0; i < adapter->num_rx_queues; i++) { | ||||
| ctrl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)); | ctrl = IXGBE_READ_REG(hw, IXGBE_VFRXDCTL(i)); | ||||
| ctrl |= IXGBE_RXDCTL_VME; | ctrl |= IXGBE_RXDCTL_VME; | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), ctrl); | IXGBE_WRITE_REG(hw, IXGBE_VFRXDCTL(i), ctrl); | ||||
| /* | /* | ||||
| * Let Rx path know that it needs to store VLAN tag | * Let Rx path know that it needs to store VLAN tag | ||||
| * as part of extra mbuf info. | * as part of extra mbuf info. | ||||
| */ | */ | ||||
| rxr = &adapter->rx_rings[i]; | adapter->rx_queues[i].rxr.vtag_strip = TRUE; | ||||
| rxr->vtag_strip = TRUE; | |||||
| } | } | ||||
| /* | /* | ||||
| ** A soft reset zero's out the VFTA, so | ** A soft reset zero's out the VFTA, so | ||||
| ** we need to repopulate it now. | ** we need to repopulate it now. | ||||
| */ | */ | ||||
| for (int i = 0; i < IXGBE_VFTA_SIZE; i++) { | for (int i = 0; i < IXGBE_VFTA_SIZE; i++) { | ||||
| if (ixv_shadow_vfta[i] == 0) | if (ixv_shadow_vfta[i] == 0) | ||||
| continue; | continue; | ||||
| vfta = ixv_shadow_vfta[i]; | vfta = ixv_shadow_vfta[i]; | ||||
| /* | /* | ||||
| ** Reconstruct the vlan id's | ** Reconstruct the vlan id's | ||||
| ** based on the bits set in each | ** based on the bits set in each | ||||
| ** of the array ints. | ** of the array ints. | ||||
| */ | */ | ||||
| for (int j = 0; j < 32; j++) { | for (int j = 0; j < 32; j++) { | ||||
| retry = 0; | retry = 0; | ||||
| if ((vfta & (1 << j)) == 0) | if ((vfta & (1 << j)) == 0) | ||||
| continue; | continue; | ||||
| vid = (i * 32) + j; | vid = (i * 32) + j; | ||||
| /* Call the shared code mailbox routine */ | /* Call the shared code mailbox routine */ | ||||
| while (ixgbe_set_vfta(hw, vid, 0, TRUE)) { | while (ixgbe_set_vfta(hw, vid, 0, TRUE, FALSE)) { | ||||
| if (++retry > 5) | if (++retry > 5) | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| ** This routine is run via an vlan config EVENT, | ** This routine is run via a vlan config EVENT, | ||||
| ** it enables us to use the HW Filter table since | ** it enables us to use the HW Filter table since | ||||
| ** we can get the vlan id. This just creates the | ** we can get the vlan id. This just creates the | ||||
| ** entry in the soft version of the VFTA, init will | ** entry in the soft version of the VFTA, init will | ||||
| ** repopulate the real table. | ** repopulate the real table. | ||||
| */ | */ | ||||
| static void | static void | ||||
| ixv_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) | ixv_if_register_vlan(if_ctx_t ctx, u16 vtag) | ||||
| { | { | ||||
| struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| u16 index, bit; | u16 index, bit; | ||||
| if (ifp->if_softc != arg) /* Not our event */ | |||||
| return; | |||||
| if ((vtag == 0) || (vtag > 4095)) /* Invalid */ | |||||
| return; | |||||
| IXGBE_CORE_LOCK(adapter); | |||||
| index = (vtag >> 5) & 0x7F; | index = (vtag >> 5) & 0x7F; | ||||
| bit = vtag & 0x1F; | bit = vtag & 0x1F; | ||||
| ixv_shadow_vfta[index] |= (1 << bit); | ixv_shadow_vfta[index] |= (1 << bit); | ||||
| ++adapter->num_vlans; | ++adapter->num_vlans; | ||||
| /* Re-init to load the changes */ | |||||
| ixv_init_locked(adapter); | |||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| } | } | ||||
| /* | /* | ||||
| ** This routine is run via an vlan | ** This routine is run via a vlan | ||||
| ** unconfig EVENT, remove our entry | ** unconfig EVENT, remove our entry | ||||
| ** in the soft vfta. | ** in the soft vfta. | ||||
| */ | */ | ||||
| static void | static void | ||||
| ixv_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) | ixv_if_unregister_vlan(if_ctx_t ctx, u16 vtag) | ||||
| { | { | ||||
| struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
| u16 index, bit; | u16 index, bit; | ||||
| if (ifp->if_softc != arg) | |||||
| return; | |||||
| if ((vtag == 0) || (vtag > 4095)) /* Invalid */ | |||||
| return; | |||||
| IXGBE_CORE_LOCK(adapter); | |||||
| index = (vtag >> 5) & 0x7F; | index = (vtag >> 5) & 0x7F; | ||||
| bit = vtag & 0x1F; | bit = vtag & 0x1F; | ||||
| ixv_shadow_vfta[index] &= ~(1 << bit); | ixv_shadow_vfta[index] &= ~(1 << bit); | ||||
| --adapter->num_vlans; | --adapter->num_vlans; | ||||
| /* Re-init to load the changes */ | |||||
| ixv_init_locked(adapter); | |||||
| IXGBE_CORE_UNLOCK(adapter); | |||||
| } | } | ||||
| static void | static void | ||||
| ixv_enable_intr(struct adapter *adapter) | ixv_if_enable_intr(if_ctx_t ctx) | ||||
| { | { | ||||
| struct adapter *adapter = iflib_get_softc(ctx); | |||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| struct ix_queue *que = adapter->queues; | struct ix_rx_queue *que = adapter->rx_queues; | ||||
| u32 mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); | u32 mask = (IXGBE_EIMS_ENABLE_MASK & ~IXGBE_EIMS_RTX_QUEUE); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); | IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); | ||||
| mask = IXGBE_EIMS_ENABLE_MASK; | mask = IXGBE_EIMS_ENABLE_MASK; | ||||
| mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC); | mask &= ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VTEIAC, mask); | IXGBE_WRITE_REG(hw, IXGBE_VTEIAC, mask); | ||||
| for (int i = 0; i < adapter->num_queues; i++, que++) | for (int i = 0; i < adapter->num_rx_queues; i++, que++) | ||||
| ixv_enable_queue(adapter, que->msix); | ixv_enable_queue(adapter, que->msix); | ||||
| IXGBE_WRITE_FLUSH(hw); | IXGBE_WRITE_FLUSH(hw); | ||||
| return; | return; | ||||
| } | } | ||||
| static void | static void | ||||
| ixv_disable_intr(struct adapter *adapter) | ixv_if_disable_intr(if_ctx_t ctx) | ||||
| { | { | ||||
| struct adapter *adapter = iflib_get_softc(ctx); | |||||
| IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEIAC, 0); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEIAC, 0); | ||||
| IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEIMC, ~0); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEIMC, ~0); | ||||
| IXGBE_WRITE_FLUSH(&adapter->hw); | IXGBE_WRITE_FLUSH(&adapter->hw); | ||||
| return; | return; | ||||
| } | } | ||||
| static int | |||||
Not Done Inline ActionsAs this always return 0 should it be a void? smh: As this always return 0 should it be a void? | |||||
| ixv_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t rxqid) | |||||
| { | |||||
| struct adapter *adapter = iflib_get_softc(ctx); | |||||
| struct ix_rx_queue *que = &adapter->rx_queues[rxqid]; | |||||
| ixv_enable_queue(adapter, que->rxr.me); | |||||
| return (0); | |||||
| } | |||||
| /* | /* | ||||
| ** Setup the correct IVAR register for a particular MSIX interrupt | ** Setup the correct IVAR register for a particular MSIX interrupt | ||||
| ** - entry is the register array entry | ** - entry is the register array entry | ||||
| ** - vector is the MSIX vector for this queue | ** - vector is the MSIX vector for this queue | ||||
| ** - type is RX/TX/MISC | ** - type is RX/TX/MISC | ||||
| */ | */ | ||||
| static void | static void | ||||
| ixv_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) | ixv_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) | ||||
| Show All 15 Lines | if (type == -1) { /* MISC IVAR */ | ||||
| ivar |= (vector << index); | ivar |= (vector << index); | ||||
| IXGBE_WRITE_REG(hw, IXGBE_VTIVAR(entry >> 1), ivar); | IXGBE_WRITE_REG(hw, IXGBE_VTIVAR(entry >> 1), ivar); | ||||
| } | } | ||||
| } | } | ||||
| static void | static void | ||||
| ixv_configure_ivars(struct adapter *adapter) | ixv_configure_ivars(struct adapter *adapter) | ||||
| { | { | ||||
| struct ix_queue *que = adapter->queues; | struct ix_rx_queue *que = adapter->rx_queues; | ||||
| for (int i = 0; i < adapter->num_queues; i++, que++) { | MPASS(adapter->num_rx_queues == adapter->num_tx_queues); | ||||
| for (int i = 0; i < adapter->num_rx_queues; i++, que++) { | |||||
| /* First the RX queue entry */ | /* First the RX queue entry */ | ||||
| ixv_set_ivar(adapter, i, que->msix, 0); | ixv_set_ivar(adapter, i, que->msix, 0); | ||||
| /* ... and the TX */ | /* ... and the TX */ | ||||
| ixv_set_ivar(adapter, i, que->msix, 1); | ixv_set_ivar(adapter, i, que->msix, 1); | ||||
| /* Set an initial value in EITR */ | /* Set an initial value in EITR */ | ||||
| IXGBE_WRITE_REG(&adapter->hw, | IXGBE_WRITE_REG(&adapter->hw, | ||||
| IXGBE_VTEITR(que->msix), IXV_EITR_DEFAULT); | IXGBE_VTEITR(que->msix), IXV_EITR_DEFAULT); | ||||
| } | } | ||||
| /* For the mailbox interrupt */ | /* For the mailbox interrupt */ | ||||
| ixv_set_ivar(adapter, 1, adapter->vector, -1); | ixv_set_ivar(adapter, 1, adapter->vector, -1); | ||||
| } | } | ||||
| /* | /* | ||||
| ** Tasklet handler for MSIX MBX interrupts | ** The VF stats registers never have a truely virgin | ||||
| ** - do outside interrupt since it might sleep | |||||
| */ | |||||
| static void | |||||
| ixv_handle_mbx(void *context, int pending) | |||||
| { | |||||
| struct adapter *adapter = context; | |||||
| ixgbe_check_link(&adapter->hw, | |||||
| &adapter->link_speed, &adapter->link_up, 0); | |||||
| ixv_update_link_status(adapter); | |||||
| } | |||||
| /* | |||||
| ** The VF stats registers never have a truly virgin | |||||
| ** starting point, so this routine tries to make an | ** starting point, so this routine tries to make an | ||||
| ** artificial one, marking ground zero on attach as | ** artificial one, marking ground zero on attach as | ||||
| ** it were. | ** it were. | ||||
| */ | */ | ||||
| static void | static void | ||||
| ixv_save_stats(struct adapter *adapter) | ixv_save_stats(struct adapter *adapter) | ||||
| { | { | ||||
| if (adapter->stats.vf.vfgprc || adapter->stats.vf.vfgptc) { | if (adapter->stats.vf.vfgprc || adapter->stats.vf.vfgptc) { | ||||
| adapter->stats.vf.saved_reset_vfgprc += | adapter->stats.vf.saved_reset_vfgprc += | ||||
| adapter->stats.vf.vfgprc - adapter->stats.vf.base_vfgprc; | adapter->stats.vf.vfgprc - adapter->stats.vf.base_vfgprc; | ||||
| adapter->stats.vf.saved_reset_vfgptc += | adapter->stats.vf.saved_reset_vfgptc += | ||||
| adapter->stats.vf.vfgptc - adapter->stats.vf.base_vfgptc; | adapter->stats.vf.vfgptc - adapter->stats.vf.base_vfgptc; | ||||
| adapter->stats.vf.saved_reset_vfgorc += | adapter->stats.vf.saved_reset_vfgorc += | ||||
| adapter->stats.vf.vfgorc - adapter->stats.vf.base_vfgorc; | adapter->stats.vf.vfgorc - adapter->stats.vf.base_vfgorc; | ||||
| adapter->stats.vf.saved_reset_vfgotc += | adapter->stats.vf.saved_reset_vfgotc += | ||||
| adapter->stats.vf.vfgotc - adapter->stats.vf.base_vfgotc; | adapter->stats.vf.vfgotc - adapter->stats.vf.base_vfgotc; | ||||
| adapter->stats.vf.saved_reset_vfmprc += | adapter->stats.vf.saved_reset_vfmprc += | ||||
| adapter->stats.vf.vfmprc - adapter->stats.vf.base_vfmprc; | adapter->stats.vf.vfmprc - adapter->stats.vf.base_vfmprc; | ||||
| } | } | ||||
| } | } | ||||
| static void | static void | ||||
| ixv_init_stats(struct adapter *adapter) | ixv_init_stats(struct adapter *adapter) | ||||
| { | { | ||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| adapter->stats.vf.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); | adapter->stats.vf.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); | ||||
| adapter->stats.vf.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); | adapter->stats.vf.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); | ||||
| adapter->stats.vf.last_vfgorc |= | adapter->stats.vf.last_vfgorc |= | ||||
| (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32); | (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32); | ||||
| adapter->stats.vf.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC); | adapter->stats.vf.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC); | ||||
| adapter->stats.vf.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB); | adapter->stats.vf.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB); | ||||
| adapter->stats.vf.last_vfgotc |= | adapter->stats.vf.last_vfgotc |= | ||||
| Show All 13 Lines | #define UPDATE_STAT_32(reg, last, count) \ | ||||
| u32 current = IXGBE_READ_REG(hw, reg); \ | u32 current = IXGBE_READ_REG(hw, reg); \ | ||||
| if (current < last) \ | if (current < last) \ | ||||
| count += 0x100000000LL; \ | count += 0x100000000LL; \ | ||||
| last = current; \ | last = current; \ | ||||
| count &= 0xFFFFFFFF00000000LL; \ | count &= 0xFFFFFFFF00000000LL; \ | ||||
| count |= current; \ | count |= current; \ | ||||
| } | } | ||||
| #define UPDATE_STAT_36(lsb, msb, last, count) \ | #define UPDATE_STAT_36(lsb, msb, last, count) \ | ||||
| { \ | { \ | ||||
| u64 cur_lsb = IXGBE_READ_REG(hw, lsb); \ | u64 cur_lsb = IXGBE_READ_REG(hw, lsb); \ | ||||
| u64 cur_msb = IXGBE_READ_REG(hw, msb); \ | u64 cur_msb = IXGBE_READ_REG(hw, msb); \ | ||||
| u64 current = ((cur_msb << 32) | cur_lsb); \ | u64 current = ((cur_msb << 32) | cur_lsb); \ | ||||
| if (current < last) \ | if (current < last) \ | ||||
| count += 0x1000000000LL; \ | count += 0x1000000000LL; \ | ||||
| last = current; \ | last = current; \ | ||||
| count &= 0xFFFFFFF000000000LL; \ | count &= 0xFFFFFFF000000000LL; \ | ||||
| count |= current; \ | count |= current; \ | ||||
| } | } | ||||
| /* | /* | ||||
| ** ixv_update_stats - Update the board statistics counters. | ** ixv_update_stats - Update the board statistics counters. | ||||
| */ | */ | ||||
| void | void | ||||
| ixv_update_stats(struct adapter *adapter) | ixv_update_stats(struct adapter *adapter) | ||||
| { | { | ||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| struct ixgbevf_hw_stats *stats = &adapter->stats.vf; | |||||
| UPDATE_STAT_32(IXGBE_VFGPRC, adapter->stats.vf.last_vfgprc, | UPDATE_STAT_32(IXGBE_VFGPRC, adapter->stats.vf.last_vfgprc, | ||||
| adapter->stats.vf.vfgprc); | adapter->stats.vf.vfgprc); | ||||
| UPDATE_STAT_32(IXGBE_VFGPTC, adapter->stats.vf.last_vfgptc, | UPDATE_STAT_32(IXGBE_VFGPTC, adapter->stats.vf.last_vfgptc, | ||||
| adapter->stats.vf.vfgptc); | adapter->stats.vf.vfgptc); | ||||
| UPDATE_STAT_36(IXGBE_VFGORC_LSB, IXGBE_VFGORC_MSB, | UPDATE_STAT_36(IXGBE_VFGORC_LSB, IXGBE_VFGORC_MSB, | ||||
| adapter->stats.vf.last_vfgorc, adapter->stats.vf.vfgorc); | adapter->stats.vf.last_vfgorc, adapter->stats.vf.vfgorc); | ||||
| UPDATE_STAT_36(IXGBE_VFGOTC_LSB, IXGBE_VFGOTC_MSB, | UPDATE_STAT_36(IXGBE_VFGOTC_LSB, IXGBE_VFGOTC_MSB, | ||||
| adapter->stats.vf.last_vfgotc, adapter->stats.vf.vfgotc); | adapter->stats.vf.last_vfgotc, adapter->stats.vf.vfgotc); | ||||
| UPDATE_STAT_32(IXGBE_VFMPRC, adapter->stats.vf.last_vfmprc, | UPDATE_STAT_32(IXGBE_VFMPRC, adapter->stats.vf.last_vfmprc, | ||||
| adapter->stats.vf.vfmprc); | adapter->stats.vf.vfmprc); | ||||
| /* Fill out the OS statistics structure */ | |||||
| IXGBE_SET_IPACKETS(adapter, stats->vfgprc); | |||||
| IXGBE_SET_OPACKETS(adapter, stats->vfgptc); | |||||
| IXGBE_SET_IBYTES(adapter, stats->vfgorc); | |||||
| IXGBE_SET_OBYTES(adapter, stats->vfgotc); | |||||
| IXGBE_SET_IMCASTS(adapter, stats->vfmprc); | |||||
| } | } | ||||
| /* | /* | ||||
| * Add statistic sysctls for the VF. | * Add statistic sysctls for the VF. | ||||
| */ | */ | ||||
| static void | static void | ||||
| ixv_add_stats_sysctls(struct adapter *adapter) | ixv_add_stats_sysctls(struct adapter *adapter) | ||||
| { | { | ||||
| device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
| struct ix_queue *que = &adapter->queues[0]; | struct ix_tx_queue *tx_que = adapter->tx_queues; | ||||
| struct tx_ring *txr = que->txr; | struct ix_rx_queue *rx_que = adapter->rx_queues; | ||||
| struct rx_ring *rxr = que->rxr; | |||||
| struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); | struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); | ||||
| struct sysctl_oid *tree = device_get_sysctl_tree(dev); | struct sysctl_oid *tree = device_get_sysctl_tree(dev); | ||||
| struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); | struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); | ||||
| struct ixgbevf_hw_stats *stats = &adapter->stats.vf; | struct ixgbevf_hw_stats *stats = &adapter->stats.vf; | ||||
| struct sysctl_oid *stat_node, *queue_node; | struct sysctl_oid *stat_node, *queue_node; | ||||
| struct sysctl_oid_list *stat_list, *queue_list; | struct sysctl_oid_list *stat_list, *queue_list; | ||||
| #define QUEUE_NAME_LEN 32 | |||||
| char namebuf[QUEUE_NAME_LEN]; | |||||
| /* Driver Statistics */ | /* Driver Statistics */ | ||||
| SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", | |||||
| CTLFLAG_RD, &adapter->dropped_pkts, | |||||
| "Driver dropped packets"); | |||||
| SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", | |||||
| CTLFLAG_RD, &adapter->mbuf_defrag_failed, | |||||
| "m_defrag() failed"); | |||||
| SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", | SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", | ||||
| CTLFLAG_RD, &adapter->watchdog_events, | CTLFLAG_RD, &adapter->watchdog_events, "Watchdog timeouts"); | ||||
| "Watchdog timeouts"); | SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", | ||||
| CTLFLAG_RD, &adapter->link_irq, "Link MSI-X IRQ Handled"); | |||||
| stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", | for (int i = 0; i < adapter->num_tx_queues; i++, tx_que++) { | ||||
| CTLFLAG_RD, NULL, | struct tx_ring *txr = &tx_que->txr; | ||||
| "VF Statistics (read from HW registers)"); | snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); | ||||
| stat_list = SYSCTL_CHILDREN(stat_node); | queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, | ||||
| CTLFLAG_RD, NULL, "Queue Name"); | |||||
| queue_list = SYSCTL_CHILDREN(queue_node); | |||||
| SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", | SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", | ||||
| CTLFLAG_RD, &stats->vfgprc, | CTLFLAG_RD, &(txr->tso_tx), "TSO"); | ||||
| "Good Packets Received"); | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", | ||||
| SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", | CTLFLAG_RD, &(txr->total_packets), "TX Packets"); | ||||
| CTLFLAG_RD, &stats->vfgorc, | } | ||||
| "Good Octets Received"); | |||||
| SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", | |||||
| CTLFLAG_RD, &stats->vfmprc, | |||||
| "Multicast Packets Received"); | |||||
| SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", | |||||
| CTLFLAG_RD, &stats->vfgptc, | |||||
| "Good Packets Transmitted"); | |||||
| SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", | |||||
| CTLFLAG_RD, &stats->vfgotc, | |||||
| "Good Octets Transmitted"); | |||||
| queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "que", | for (int i = 0; i < adapter->num_rx_queues; i++, rx_que++) { | ||||
| CTLFLAG_RD, NULL, | struct rx_ring *rxr = &rx_que->rxr; | ||||
| "Queue Statistics (collected by SW)"); | snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); | ||||
| queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, | |||||
| CTLFLAG_RD, NULL, "Queue Name"); | |||||
| queue_list = SYSCTL_CHILDREN(queue_node); | queue_list = SYSCTL_CHILDREN(queue_node); | ||||
| SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", | ||||
| CTLFLAG_RD, &(que->irqs), | CTLFLAG_RD, &(rx_que->irqs), "IRQs on queue"); | ||||
| "IRQs on queue"); | |||||
| SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_irqs", | |||||
| CTLFLAG_RD, &(rxr->rx_irq), | |||||
| "RX irqs on queue"); | |||||
| SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", | ||||
| CTLFLAG_RD, &(rxr->rx_packets), | CTLFLAG_RD, &rxr->rx_packets, "Queue Packets Received"); | ||||
| "RX packets"); | |||||
| SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", | ||||
| CTLFLAG_RD, &(rxr->rx_bytes), | CTLFLAG_RD, &rxr->rx_bytes, "Queue Bytes Received"); | ||||
| "RX bytes"); | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", | ||||
| SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_discarded", | CTLFLAG_RD, &rxr->rx_copies, "Copied RX Frames"); | ||||
| CTLFLAG_RD, &(rxr->rx_discarded), | } | ||||
| "Discarded RX packets"); | |||||
| SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", | stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", | ||||
| CTLFLAG_RD, &(txr->total_packets), | CTLFLAG_RD, NULL, "VF Statistics (read from HW registers)"); | ||||
| "TX Packets"); | stat_list = SYSCTL_CHILDREN(stat_node); | ||||
| SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_no_desc", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", | ||||
| CTLFLAG_RD, &(txr->no_desc_avail), | CTLFLAG_RD, &stats->vfgprc, "Good Packets Received"); | ||||
| "# of times not enough descriptors were available during TX"); | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", | ||||
| CTLFLAG_RD, &stats->vfgorc, "Good Octets Received"); | |||||
| SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", | |||||
| CTLFLAG_RD, &stats->vfmprc, "Multicast Packets Received"); | |||||
| SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", | |||||
| CTLFLAG_RD, &stats->vfgptc, "Good Packets Transmitted"); | |||||
| SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", | |||||
| CTLFLAG_RD, &stats->vfgotc, "Good Octets Transmitted"); | |||||
| } | } | ||||
| static void | static void | ||||
| ixv_set_sysctl_value(struct adapter *adapter, const char *name, | ixv_set_sysctl_value(struct adapter *adapter, const char *name, | ||||
| const char *description, int *limit, int value) | const char *description, int *limit, int value) | ||||
| { | { | ||||
| *limit = value; | *limit = value; | ||||
| SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev), | SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev), | ||||
| SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), | SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), | ||||
| OID_AUTO, name, CTLFLAG_RW, limit, value, description); | OID_AUTO, name, CTLFLAG_RW, limit, value, description); | ||||
| } | } | ||||
| /********************************************************************** | /********************************************************************** | ||||
| * | * | ||||
| * This routine is called only when em_display_debug_stats is enabled. | * This routine is called only when em_display_debug_stats is enabled. | ||||
| * This routine provides a way to take a look at important statistics | * This routine provides a way to take a look at important statistics | ||||
| * maintained by the driver and hardware. | * maintained by the driver and hardware. | ||||
| * | * | ||||
| **********************************************************************/ | **********************************************************************/ | ||||
| static void | static void | ||||
| ixv_print_debug_info(struct adapter *adapter) | ixv_print_debug_info(struct adapter *adapter) | ||||
| { | { | ||||
| device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
| struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
| struct ix_queue *que = adapter->queues; | |||||
| struct rx_ring *rxr; | |||||
| struct tx_ring *txr; | |||||
| struct lro_ctrl *lro; | |||||
| device_printf(dev,"Error Byte Count = %u \n", | device_printf(dev, "Error Byte Count = %u \n", | ||||
| IXGBE_READ_REG(hw, IXGBE_ERRBC)); | IXGBE_READ_REG(hw, IXGBE_ERRBC)); | ||||
| for (int i = 0; i < adapter->num_queues; i++, que++) { | device_printf(dev, "MBX IRQ Handled: %lu\n", (long)adapter->link_irq); | ||||
| txr = que->txr; | |||||
| rxr = que->rxr; | |||||
| lro = &rxr->lro; | |||||
| device_printf(dev,"QUE(%d) IRQs Handled: %lu\n", | |||||
| que->msix, (long)que->irqs); | |||||
| device_printf(dev,"RX(%d) Packets Received: %lld\n", | |||||
| rxr->me, (long long)rxr->rx_packets); | |||||
| device_printf(dev,"RX(%d) Bytes Received: %lu\n", | |||||
| rxr->me, (long)rxr->rx_bytes); | |||||
| device_printf(dev,"RX(%d) LRO Queued= %lld\n", | |||||
| rxr->me, (long long)lro->lro_queued); | |||||
| device_printf(dev,"RX(%d) LRO Flushed= %lld\n", | |||||
| rxr->me, (long long)lro->lro_flushed); | |||||
| device_printf(dev,"TX(%d) Packets Sent: %lu\n", | |||||
| txr->me, (long)txr->total_packets); | |||||
| device_printf(dev,"TX(%d) NO Desc Avail: %lu\n", | |||||
| txr->me, (long)txr->no_desc_avail); | |||||
| } | |||||
| device_printf(dev,"MBX IRQ Handled: %lu\n", | |||||
| (long)adapter->link_irq); | |||||
| return; | return; | ||||
Not Done Inline Actionsreturn not needed smh: return not needed | |||||
| } | } | ||||
| static int | static int | ||||
| ixv_sysctl_debug(SYSCTL_HANDLER_ARGS) | ixv_sysctl_debug(SYSCTL_HANDLER_ARGS) | ||||
| { | { | ||||
| int error, result; | int error, result; | ||||
| struct adapter *adapter; | struct adapter *adapter; | ||||
| result = -1; | result = -1; | ||||
| error = sysctl_handle_int(oidp, &result, 0, req); | error = sysctl_handle_int(oidp, &result, 0, req); | ||||
| if (error || !req->newptr) | if (error || !req->newptr) | ||||
| return (error); | return (error); | ||||
| if (result == 1) { | if (result == 1) { | ||||
| adapter = (struct adapter *) arg1; | adapter = (struct adapter *)arg1; | ||||
| ixv_print_debug_info(adapter); | ixv_print_debug_info(adapter); | ||||
| } | } | ||||
| return error; | return error; | ||||
| } | } | ||||
| /************************************************************************ | |||||
| * ixv_init_device_features | |||||
| ************************************************************************/ | |||||
| static void | |||||
| ixv_init_device_features(struct adapter *adapter) | |||||
| { | |||||
| adapter->feat_cap = IXGBE_FEATURE_NETMAP | |||||
| | IXGBE_FEATURE_VF | |||||
| | IXGBE_FEATURE_RSS; | |||||
| /* A tad short on feature flags for VFs, atm. */ | |||||
| switch (adapter->hw.mac.type) { | |||||
| case ixgbe_mac_82599_vf: | |||||
| adapter->feat_cap |= IXGBE_FEATURE_FRAME_LIMIT; | |||||
| break; | |||||
| case ixgbe_mac_X540_vf: | |||||
| break; | |||||
| case ixgbe_mac_X550_vf: | |||||
| case ixgbe_mac_X550EM_x_vf: | |||||
| case ixgbe_mac_X550EM_a_vf: | |||||
| adapter->feat_cap |= IXGBE_FEATURE_NEEDS_CTXD; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| /* Enabled by default... */ | |||||
| /* Is a virtual function (VF) */ | |||||
| if (adapter->feat_cap & IXGBE_FEATURE_VF) | |||||
| adapter->feat_en |= IXGBE_FEATURE_VF; | |||||
| /* Netmap */ | |||||
| if (adapter->feat_cap & IXGBE_FEATURE_NETMAP) | |||||
| adapter->feat_en |= IXGBE_FEATURE_NETMAP; | |||||
| /* Receive-Side Scaling (RSS) */ | |||||
| if (adapter->feat_cap & IXGBE_FEATURE_RSS) | |||||
| adapter->feat_en |= IXGBE_FEATURE_RSS; | |||||
| /* Frame size limitation */ | |||||
| if (adapter->feat_cap & IXGBE_FEATURE_FRAME_LIMIT) | |||||
| adapter->feat_en |= IXGBE_FEATURE_FRAME_LIMIT; | |||||
| /* Needs advanced context descriptor regardless of offloads req'd */ | |||||
| if (adapter->feat_cap & IXGBE_FEATURE_NEEDS_CTXD) | |||||
| adapter->feat_en |= IXGBE_FEATURE_NEEDS_CTXD; | |||||
| } /* ixv_init_device_features */ | |||||