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.11-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 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_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 = PAGE_SIZE*4, | |||||
.isc_rx_nsegments = 1, | |||||
.isc_rx_maxsegsize = PAGE_SIZE*4, | |||||
.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))) { | ||||
Not Done Inline ActionsLong line smh: Long line | |||||
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++) | |||||
txr->tx_rsq[j] = QIDX_INVALID; | |||||
/* get the virtual and physical address of the hardware queues */ | |||||
txr->tail = IXGBE_TDT(txr->me); | |||||
txr->tx_base = (union ixgbe_adv_tx_desc *)vaddrs[i]; | |||||
txr->tx_paddr = paddrs[i]; | |||||
((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) { | |||||
Not Done Inline Actions== NULL smh: == NULL | |||||
device_printf(iflib_get_dev(ctx), | |||||
"Unable to allocate TX ring memory\n"); | |||||
return (ENOMEM); | |||||
} | } | ||||
for (i = 0, que = adapter->rx_queues; i < nrxqsets; i++, que++) { | |||||
struct rx_ring *rxr = &que->rxr; | |||||
Not Done Inline Actionsformatting smh: formatting | |||||
rxr->me = i; | |||||
rxr->adapter = que->adapter = adapter; | |||||
/* get the virtual and physical address of the hardware queues */ | |||||
rxr->tail = IXGBE_RDT(rxr->me); | |||||
rxr->rx_base = (union ixgbe_adv_rx_desc *)vaddrs[i]; | |||||
rxr->rx_paddr = paddrs[i]; | |||||
rxr->bytes = 0; | |||||
rxr->que = que; | |||||
} | |||||
device_printf(iflib_get_dev(ctx), "allocated for %d rx queues\n", adapter->num_rx_queues); | |||||
return (0); | |||||
ixv_if_queues_free(ctx); | |||||
return (error); | |||||
} | |||||
static void | |||||
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) | |||||
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) | |||||
Not Done Inline ActionsI thought the kernel free checked this already? Same above smh: I thought the kernel free checked this already? Same above | |||||
free(adapter->rx_queues, M_DEVBUF); | |||||
adapter->tx_queues = NULL; | |||||
Not Done Inline ActionsMove above free. smh: Move above free. | |||||
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); | ||||
adapter = iflib_get_softc(ctx); | |||||
adapter->dev = dev; | adapter->dev = dev; | ||||
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 */ | scctx->isc_txqsizes[0] = | ||||
ixv_save_stats(adapter); | roundup2(scctx->isc_ntxd[0] * sizeof(union ixgbe_adv_tx_desc) + | ||||
ixv_init_stats(adapter); | sizeof(u32), DBA_ALIGN); | ||||
ixv_add_stats_sysctls(adapter); | 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 | |||||
*/ | |||||
scctx->isc_capenable = IXGBE_CAPS; | |||||
scctx->isc_capenable ^= IFCAP_HWSTATS | IFCAP_VLAN_HWFILTER | IFCAP_WOL; | |||||
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; | ||||
adapter->max_frame_size = | |||||
ifp->if_mtu + IXGBE_MTU_HDR; | |||||
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 */ | /* Set the various hardware offload abilities */ | ||||
ifp->if_hwassist = 0; | ifp->if_hwassist = 0; | ||||
if (ifp->if_capenable & IFCAP_TSO4) | if (ifp->if_capenable & IFCAP_TSO4) | ||||
ifp->if_hwassist |= CSUM_TSO; | ifp->if_hwassist |= CSUM_TSO; | ||||
if (ifp->if_capenable & IFCAP_TXCSUM) { | if (ifp->if_capenable & IFCAP_TXCSUM) { | ||||
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | ||||
#if __FreeBSD_version >= 800000 | #if __FreeBSD_version >= 800000 | ||||
ifp->if_hwassist |= CSUM_SCTP; | ifp->if_hwassist |= CSUM_SCTP; | ||||
#endif | #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 */ | |||||
ixv_enable_intr(adapter); | |||||
/* 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) | ||||
Show All 20 Lines | |||||
static inline void | static inline void | ||||
ixv_rearm_queues(struct adapter *adapter, u64 queues) | ixv_rearm_queues(struct adapter *adapter, u64 queues) | ||||
{ | { | ||||
u32 mask = (IXGBE_EIMS_RTX_QUEUE & queues); | u32 mask = (IXGBE_EIMS_RTX_QUEUE & queues); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEICS, mask); | 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 = adapter->media; | ||||
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; | ||||
} | } | ||||
Show All 19 Lines | |||||
* 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); | ixv_if_update_admin_status(ctx); | ||||
/* Stats Update */ | /* Stats Update */ | ||||
ixv_update_stats(adapter); | ixv_update_stats(adapter); | ||||
/* | |||||
** Check the TX queues status | |||||
** - 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; | |||||
} | |||||
} | |||||
/* Only truly watchdog if all queues show hung */ | |||||
if (hung == adapter->num_queues) | |||||
goto watchdog; | |||||
else if (queues != 0) { /* Force an IRQ on queues with work */ | |||||
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 | ** Note: this routine updates the OS on the link state | ||||
** the real check of the hardware only happens with | ** the real check of the hardware only happens with | ||||
** a link interrupt. | ** 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 */ | |||||
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); | |||||
/* 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 = adapter->tx_queues; | |||||
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++, tx_que++) { | ||||
rid = vector + 1; | snprintf(buf, sizeof(buf), "txq%d", i); | ||||
adapter->res = bus_alloc_resource_any(dev, | iflib_softirq_alloc_generic(ctx, rid, IFLIB_INTR_TX, tx_que, | ||||
SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); | tx_que->txr.me, buf); | ||||
if (!adapter->res) { | |||||
device_printf(dev,"Unable to allocate" | |||||
" 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); | |||||
/* | for (int i = 0; i < adapter->num_rx_queues; i++, que++) { | ||||
** There is a slight possibility of a failure mode | iflib_irq_free(ctx, &que->que_irq); | ||||
** in attach that will result in entering this function | |||||
** before interrupt resources have been initialized, and | |||||
** in that case we do not want to execute the loops below | |||||
** We can detect this reliably by the state of the adapter | |||||
** res pointer. | |||||
*/ | |||||
if (adapter->res == NULL) | |||||
goto mem; | |||||
/* | |||||
** Release all msix queue resources: | |||||
*/ | |||||
for (int i = 0; i < adapter->num_queues; i++, que++) { | |||||
rid = que->msix + 1; | |||||
if (que->tag != NULL) { | |||||
bus_teardown_intr(dev, que->res, que->tag); | |||||
que->tag = NULL; | |||||
} | } | ||||
if (que->res != NULL) | |||||
bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); | |||||
} | |||||
/* Clean the Legacy or Link interrupt last */ | /* 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; | ||||
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 | |||||
ixv_config_link(struct adapter *adapter) | |||||
{ | |||||
struct ixgbe_hw *hw = &adapter->hw; | |||||
u32 autoneg; | |||||
if (hw->mac.ops.check_link) | |||||
hw->mac.ops.check_link(hw, &autoneg, | |||||
&adapter->link_up, FALSE); | |||||
} | |||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* 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); | ||||
/* 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 | #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) { | ||||
/* | |||||
* Workaround for hardware that can't support frames with VLAN | |||||
* headers without turning on jumbo frames in the PF driver. | |||||
*/ | |||||
if (adapter->feat_en & IXGBE_FEATURE_FRAME_LIMIT) { | |||||
Not Done Inline Actions!= 0 smh: != 0 | |||||
device_printf(adapter->dev, "This is a device with a frame size limitation. The PF driver is forced to deny a change in frame size to allow for VLAN headers while jumbo frames is not enabled. To work around this, we're telling the stack that the MTU must shrink by sizeof(VLAN header) if VLANs are enabled. Thus, our maximum frame size is standard MTU + ethernet header/CRC. If you want standard MTU plus VLAN headers, you can also enable jumbo frames in the PF first.\n"); | |||||
Not Done Inline ActionsLong line. smh: Long line. | |||||
adapter->max_frame_size = ifp->if_mtu + IXGBE_MTU_HDR; | |||||
if_setcapabilitiesbit(ifp, 0, IFCAP_VLAN_MTU); | |||||
if_setcapenablebit(ifp, 0, IFCAP_VLAN_MTU); | |||||
} | |||||
/* Try again... */ | |||||
if (ixgbevf_rlpml_set_vf(hw, adapter->max_frame_size)) { | |||||
Not Done Inline Actions!= 0 or == 1? smh: != 0 or == 1? | |||||
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"); | |||||
Not Done Inline ActionsLong line smh: Long line | |||||
} | |||||
} | |||||
scctx = adapter->shared; | |||||
for (int i = 0; i < adapter->num_queues; i++, rxr++) { | for (int i = 0; i < adapter->num_rx_queues; i++, que++) { | ||||
u64 rdba = rxr->rxdma.dma_paddr; | struct rx_ring *rxr = &que->rxr; | ||||
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)); | ||||
rxdctl &= ~IXGBE_RXDCTL_ENABLE; | rxdctl &= ~IXGBE_RXDCTL_ENABLE; | ||||
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 an 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 an 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; | ||||
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); | ||||
} | } | ||||
/* | /* | ||||
* 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 tx_ring *txr = que->txr; | |||||
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; | ||||
struct sysctl_oid_list *stat_list, *queue_list; | struct sysctl_oid_list *stat_list; | ||||
/* 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"); | ||||
stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", | stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", | ||||
CTLFLAG_RD, NULL, | CTLFLAG_RD, NULL, | ||||
"VF Statistics (read from HW registers)"); | "VF Statistics (read from HW registers)"); | ||||
stat_list = SYSCTL_CHILDREN(stat_node); | stat_list = SYSCTL_CHILDREN(stat_node); | ||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", | ||||
CTLFLAG_RD, &stats->vfgprc, | CTLFLAG_RD, &stats->vfgprc, | ||||
"Good Packets Received"); | "Good Packets Received"); | ||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", | ||||
CTLFLAG_RD, &stats->vfgorc, | CTLFLAG_RD, &stats->vfgorc, | ||||
"Good Octets Received"); | "Good Octets Received"); | ||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", | ||||
CTLFLAG_RD, &stats->vfmprc, | CTLFLAG_RD, &stats->vfmprc, | ||||
"Multicast Packets Received"); | "Multicast Packets Received"); | ||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", | ||||
CTLFLAG_RD, &stats->vfgptc, | CTLFLAG_RD, &stats->vfgptc, | ||||
"Good Packets Transmitted"); | "Good Packets Transmitted"); | ||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", | ||||
CTLFLAG_RD, &stats->vfgotc, | CTLFLAG_RD, &stats->vfgotc, | ||||
"Good Octets Transmitted"); | "Good Octets Transmitted"); | ||||
queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "que", | |||||
CTLFLAG_RD, NULL, | |||||
"Queue Statistics (collected by SW)"); | |||||
queue_list = SYSCTL_CHILDREN(queue_node); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", | |||||
CTLFLAG_RD, &(que->irqs), | |||||
"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", | |||||
CTLFLAG_RD, &(rxr->rx_packets), | |||||
"RX packets"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", | |||||
CTLFLAG_RD, &(rxr->rx_bytes), | |||||
"RX bytes"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_discarded", | |||||
CTLFLAG_RD, &(rxr->rx_discarded), | |||||
"Discarded RX packets"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", | |||||
CTLFLAG_RD, &(txr->total_packets), | |||||
"TX Packets"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_no_desc", | |||||
CTLFLAG_RD, &(txr->no_desc_avail), | |||||
"# of times not enough descriptors were available during TX"); | |||||
} | } | ||||
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 */ | |||||