Changeset View
Standalone View
sys/dev/ixgbe/if_ixv.c
Show All 27 Lines | /****************************************************************************** | ||||
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.5.13-k"; | char ixv_driver_version[] = "1.5.13-k"; | ||||
/************************************************************************ | /************************************************************************ | ||||
* PCI Device ID Table | * PCI Device ID Table | ||||
* | * | ||||
* Used by probe to select devices to load on | * Used by probe to select devices to load on | ||||
* Last field stores an index into ixv_strings | * Last field stores an index into ixv_strings | ||||
* Last entry must be all 0s | * Last entry must be all 0s | ||||
* | * | ||||
* { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } | * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, String Index } | ||||
************************************************************************/ | ************************************************************************/ | ||||
static ixgbe_vendor_info_t ixv_vendor_info_array[] = | static pci_vendor_info_t ixv_vendor_info_array[] = | ||||
{ | { | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_VF, 0, 0, 0}, | PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82599_VF, "Intel(R) PRO/10GbE Virtual Function Network Driver"), | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_VF, 0, 0, 0}, | PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X540_VF, "Intel(R) PRO/10GbE Virtual Function Network Driver"), | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550_VF, 0, 0, 0}, | PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550_VF, "Intel(R) PRO/10GbE Virtual Function Network Driver"), | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_VF, 0, 0, 0}, | PVID(IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_VF, "Intel(R) PRO/10GbE Virtual Function Network Driver"), | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_A_VF, 0, 0, 0}, | 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 | |||||
************************************************************************/ | |||||
static char *ixv_strings[] = { | |||||
"Intel(R) PRO/10GbE Virtual Function Network Driver" | |||||
}; | |||||
/************************************************************************ | |||||
* Function prototypes | * Function prototypes | ||||
************************************************************************/ | ************************************************************************/ | ||||
static int ixv_probe(device_t); | static void *ixv_register(device_t dev); | ||||
static int ixv_attach(device_t); | static int ixv_if_attach_pre(if_ctx_t ctx); | ||||
static int ixv_detach(device_t); | static int ixv_if_attach_post(if_ctx_t ctx); | ||||
static int ixv_shutdown(device_t); | static int ixv_if_detach(if_ctx_t ctx); | ||||
static int ixv_ioctl(struct ifnet *, u_long, caddr_t); | |||||
static void ixv_init(void *); | static int ixv_if_rx_queue_intr_enable(if_ctx_t ctx, uint16_t qid); | ||||
static void ixv_init_locked(struct adapter *); | static int ixv_if_tx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nqs, int nqsets); | ||||
static void ixv_stop(void *); | static int ixv_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, int nqs, int nqsets); | ||||
static uint64_t ixv_get_counter(struct ifnet *, ift_counter); | 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 void ixv_init_device_features(struct adapter *); | ||||
static void ixv_media_status(struct ifnet *, struct ifmediareq *); | static int ixv_allocate_pci_resources(if_ctx_t ctx); | ||||
static int ixv_media_change(struct ifnet *); | static void ixv_free_pci_resources(if_ctx_t ctx); | ||||
static int ixv_allocate_pci_resources(struct adapter *); | static int ixv_setup_interface(if_ctx_t ctx); | ||||
static int ixv_allocate_msix(struct adapter *); | static void ixv_if_media_status(if_ctx_t , struct ifmediareq *); | ||||
static int ixv_configure_interrupts(struct adapter *); | static int ixv_if_media_change(if_ctx_t ctx); | ||||
static void ixv_free_pci_resources(struct adapter *); | static void ixv_if_update_admin_status(if_ctx_t ctx); | ||||
static void ixv_local_timer(void *); | static int ixv_if_msix_intr_assign(if_ctx_t ctx, int msix); | ||||
static void ixv_setup_interface(device_t, struct adapter *); | |||||
static int ixv_if_mtu_set(if_ctx_t ctx, uint32_t mtu); | |||||
static void ixv_if_init(if_ctx_t ctx); | |||||
static void ixv_if_local_timer(if_ctx_t ctx, uint16_t qid); | |||||
static void ixv_if_stop(if_ctx_t ctx); | |||||
static int ixv_negotiate_api(struct adapter *); | static int ixv_negotiate_api(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_initialize_rss_mapping(struct adapter *); | ||||
static void ixv_check_link(struct adapter *); | |||||
static void ixv_enable_intr(struct adapter *); | static void ixv_setup_vlan_support(if_ctx_t ctx); | ||||
static void ixv_disable_intr(struct adapter *); | |||||
static void ixv_set_multi(struct adapter *); | |||||
static void ixv_update_link_status(struct adapter *); | |||||
static int ixv_sysctl_debug(SYSCTL_HANDLER_ARGS); | |||||
static void ixv_set_ivar(struct adapter *, u8, u8, s8); | |||||
static void ixv_configure_ivars(struct adapter *); | static void ixv_configure_ivars(struct adapter *); | ||||
static u8 *ixv_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); | static void ixv_if_enable_intr(if_ctx_t ctx); | ||||
static void ixv_if_disable_intr(if_ctx_t ctx); | |||||
static void ixv_if_multi_set(if_ctx_t ctx); | |||||
static void ixv_setup_vlan_support(struct adapter *); | static void ixv_if_register_vlan(if_ctx_t, u16); | ||||
static void ixv_register_vlan(void *, struct ifnet *, u16); | static void ixv_if_unregister_vlan(if_ctx_t, u16); | ||||
static void ixv_unregister_vlan(void *, struct ifnet *, u16); | |||||
static uint64_t ixv_if_get_counter(if_ctx_t, ift_counter); | |||||
static void ixv_save_stats(struct adapter *); | static void ixv_save_stats(struct adapter *); | ||||
static void ixv_init_stats(struct adapter *); | static void ixv_init_stats(struct adapter *); | ||||
static void ixv_update_stats(struct adapter *); | static void ixv_update_stats(struct adapter *); | ||||
static void ixv_add_stats_sysctls(struct adapter *); | static void ixv_add_stats_sysctls(struct adapter *adapter); | ||||
static int ixv_sysctl_debug(SYSCTL_HANDLER_ARGS); | |||||
static void ixv_set_ivar(struct adapter *, u8, u8, s8); | |||||
static u8 *ixv_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); | |||||
static void ixv_set_sysctl_value(struct adapter *, const char *, | static void ixv_set_sysctl_value(struct adapter *, const char *, | ||||
const char *, int *, int); | const char *, int *, int); | ||||
/* The MSI-X Interrupt handlers */ | /* The MSI-X Interrupt handlers */ | ||||
static void ixv_msix_que(void *); | static int ixv_msix_que(void *); | ||||
static void ixv_msix_mbx(void *); | static int ixv_msix_mbx(void *); | ||||
/* Deferred interrupt tasklets */ | |||||
static void ixv_handle_que(void *, int); | |||||
static void ixv_handle_link(void *, int); | |||||
/************************************************************************ | /************************************************************************ | ||||
* 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 | |||||
MODULE_DEPEND(ixv, netmap, 1, 1, 1); | MODULE_DEPEND(ixv, netmap, 1, 1, 1); | ||||
#endif /* DEV_NETMAP */ | |||||
static device_method_t ixv_if_methods[] = { | |||||
DEVMETHOD(ifdi_attach_pre, ixv_if_attach_pre), | |||||
DEVMETHOD(ifdi_attach_post, ixv_if_attach_post), | |||||
DEVMETHOD(ifdi_detach, ixv_if_detach), | |||||
DEVMETHOD(ifdi_init, ixv_if_init), | |||||
DEVMETHOD(ifdi_stop, ixv_if_stop), | |||||
DEVMETHOD(ifdi_msix_intr_assign, ixv_if_msix_intr_assign), | |||||
DEVMETHOD(ifdi_intr_enable, ixv_if_enable_intr), | |||||
DEVMETHOD(ifdi_intr_disable, ixv_if_disable_intr), | |||||
DEVMETHOD(ifdi_tx_queue_intr_enable, ixv_if_rx_queue_intr_enable), | |||||
DEVMETHOD(ifdi_rx_queue_intr_enable, ixv_if_rx_queue_intr_enable), | |||||
DEVMETHOD(ifdi_tx_queues_alloc, ixv_if_tx_queues_alloc), | |||||
DEVMETHOD(ifdi_rx_queues_alloc, ixv_if_rx_queues_alloc), | |||||
DEVMETHOD(ifdi_queues_free, ixv_if_queues_free), | |||||
DEVMETHOD(ifdi_update_admin_status, ixv_if_update_admin_status), | |||||
DEVMETHOD(ifdi_multi_set, ixv_if_multi_set), | |||||
DEVMETHOD(ifdi_mtu_set, ixv_if_mtu_set), | |||||
DEVMETHOD(ifdi_media_status, ixv_if_media_status), | |||||
DEVMETHOD(ifdi_media_change, ixv_if_media_change), | |||||
DEVMETHOD(ifdi_timer, ixv_if_local_timer), | |||||
DEVMETHOD(ifdi_vlan_register, ixv_if_register_vlan), | |||||
DEVMETHOD(ifdi_vlan_unregister, ixv_if_unregister_vlan), | |||||
DEVMETHOD(ifdi_get_counter, ixv_if_get_counter), | |||||
DEVMETHOD_END | |||||
}; | |||||
static driver_t ixv_if_driver = { | |||||
"ixv_if", ixv_if_methods, sizeof(struct adapter) | |||||
}; | |||||
/* | /* | ||||
* TUNEABLE PARAMETERS: | * TUNEABLE PARAMETERS: | ||||
*/ | */ | ||||
/* Number of Queues - do not exceed MSI-X vectors - 1 */ | |||||
static int ixv_num_queues = 1; | |||||
TUNABLE_INT("hw.ixv.num_queues", &ixv_num_queues); | |||||
/* | /* | ||||
sbruno: Oh ... this should be dropped now that we configure number of queues via iflib. | |||||
* AIM: Adaptive Interrupt Moderation | * AIM: Adaptive Interrupt Moderation | ||||
* which means that the interrupt rate | * which means that the interrupt rate | ||||
* is varied over time based on the | * is varied over time based on the | ||||
* traffic for that interrupt vector | * traffic for that interrupt vector | ||||
*/ | */ | ||||
static int ixv_enable_aim = FALSE; | static int ixv_enable_aim = FALSE; | ||||
TUNABLE_INT("hw.ixv.enable_aim", &ixv_enable_aim); | TUNABLE_INT("hw.ixv.enable_aim", &ixv_enable_aim); | ||||
/* How many packets rxeof tries to clean at a time */ | |||||
static int ixv_rx_process_limit = 256; | |||||
TUNABLE_INT("hw.ixv.rx_process_limit", &ixv_rx_process_limit); | |||||
/* How many packets txeof tries to clean at a time */ | |||||
static int ixv_tx_process_limit = 256; | |||||
TUNABLE_INT("hw.ixv.tx_process_limit", &ixv_tx_process_limit); | |||||
/* Flow control setting, default to full */ | /* Flow control setting, default to full */ | ||||
static int ixv_flow_control = ixgbe_fc_full; | static int ixv_flow_control = ixgbe_fc_full; | ||||
TUNABLE_INT("hw.ixv.flow_control", &ixv_flow_control); | TUNABLE_INT("hw.ixv.flow_control", &ixv_flow_control); | ||||
/* | /* | ||||
* Header split: this causes the hardware to DMA | * Header split: this causes the hardware to DMA | ||||
* the header into a separate mbuf from the payload, | * the header into a separate mbuf from the payload, | ||||
* it can be a performance win in some workloads, but | * it can be a performance win in some workloads, but | ||||
* in others it actually hurts, its off by default. | * in others it actually hurts, its off by default. | ||||
*/ | */ | ||||
static int ixv_header_split = FALSE; | static int ixv_header_split = FALSE; | ||||
TUNABLE_INT("hw.ixv.hdr_split", &ixv_header_split); | TUNABLE_INT("hw.ixv.hdr_split", &ixv_header_split); | ||||
/* | /* | ||||
* Number of TX descriptors per ring, | |||||
* setting higher than RX as this seems | |||||
* the better performing choice. | |||||
*/ | |||||
static int ixv_txd = DEFAULT_TXD; | |||||
TUNABLE_INT("hw.ixv.txd", &ixv_txd); | |||||
/* Number of RX descriptors per ring */ | |||||
static int ixv_rxd = DEFAULT_RXD; | |||||
TUNABLE_INT("hw.ixv.rxd", &ixv_rxd); | |||||
/* Legacy Transmit (single queue) */ | |||||
static int ixv_enable_legacy_tx = 0; | |||||
TUNABLE_INT("hw.ixv.enable_legacy_tx", &ixv_enable_legacy_tx); | |||||
/* | |||||
* Shadow VFTA table, this is needed because | * Shadow VFTA table, this is needed because | ||||
Not Done Inline ActionsThese two values should be dropped now that we configure things via iflib. sbruno: These two values should be dropped now that we configure things via iflib. | |||||
* 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 int (*ixv_start_locked)(struct ifnet *, struct tx_ring *); | static struct if_shared_ctx ixv_sctx_init = { | ||||
static int (*ixv_ring_empty)(struct ifnet *, struct buf_ring *); | .isc_magic = IFLIB_MAGIC, | ||||
.isc_q_align = PAGE_SIZE,/* max(DBA_ALIGN, PAGE_SIZE) */ | |||||
.isc_tx_maxsize = IXGBE_TSO_SIZE, | |||||
.isc_tx_maxsegsize = PAGE_SIZE, | |||||
.isc_rx_maxsize = MJUM16BYTES, | |||||
.isc_rx_nsegments = 1, | |||||
.isc_rx_maxsegsize = MJUM16BYTES, | |||||
.isc_nfl = 1, | |||||
.isc_ntxqs = 1, | |||||
.isc_nrxqs = 1, | |||||
.isc_admin_intrcnt = 1, | |||||
.isc_vendor_info = ixv_vendor_info_array, | |||||
.isc_driver_version = ixv_driver_version, | |||||
.isc_driver = &ixv_if_driver, | |||||
.isc_nrxd_min = {MIN_RXD}, | |||||
.isc_ntxd_min = {MIN_TXD}, | |||||
.isc_nrxd_max = {MAX_RXD}, | |||||
.isc_ntxd_max = {MAX_TXD}, | |||||
.isc_nrxd_default = {DEFAULT_RXD}, | |||||
.isc_ntxd_default = {DEFAULT_TXD}, | |||||
}; | |||||
if_shared_ctx_t ixv_sctx = &ixv_sctx_init; | |||||
static void * | |||||
ixv_register(device_t dev) | |||||
{ | |||||
return (ixv_sctx); | |||||
} | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_probe - Device identification routine | * ixv_if_tx_queues_alloc | ||||
* | |||||
* Determines if the driver should be loaded on | |||||
* adapter based on its PCI vendor/device ID. | |||||
* | |||||
* return BUS_PROBE_DEFAULT on success, positive on failure | |||||
************************************************************************/ | ************************************************************************/ | ||||
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); | ||||
u16 pci_vendor_id = 0; | if_softc_ctx_t scctx = adapter->shared; | ||||
u16 pci_device_id = 0; | struct ix_tx_queue *que; | ||||
u16 pci_subvendor_id = 0; | int i, j, error; | ||||
u16 pci_subdevice_id = 0; | |||||
char adapter_name[256]; | |||||
MPASS(adapter->num_tx_queues == ntxqsets); | |||||
MPASS(ntxqs == 1); | |||||
pci_vendor_id = pci_get_vendor(dev); | /* Allocate queue structure memory */ | ||||
if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) | adapter->tx_queues = | ||||
return (ENXIO); | (struct ix_tx_queue *)malloc(sizeof(struct ix_tx_queue) * ntxqsets, | ||||
M_DEVBUF, M_NOWAIT | M_ZERO); | |||||
if (!adapter->tx_queues) { | |||||
device_printf(iflib_get_dev(ctx), | |||||
"Unable to allocate TX ring memory\n"); | |||||
return (ENOMEM); | |||||
} | |||||
pci_device_id = pci_get_device(dev); | for (i = 0, que = adapter->tx_queues; i < ntxqsets; i++, que++) { | ||||
pci_subvendor_id = pci_get_subvendor(dev); | struct tx_ring *txr = &que->txr; | ||||
pci_subdevice_id = pci_get_subdevice(dev); | |||||
ent = ixv_vendor_info_array; | txr->me = i; | ||||
while (ent->vendor_id != 0) { | txr->adapter = que->adapter = adapter; | ||||
if ((pci_vendor_id == ent->vendor_id) && | adapter->active_queues |= (u64)1 << txr->me; | ||||
(pci_device_id == ent->device_id) && | |||||
((pci_subvendor_id == ent->subvendor_id) || | /* Allocate report status array */ | ||||
(ent->subvendor_id == 0)) && | if (!(txr->tx_rsq = (qidx_t *)malloc(sizeof(qidx_t) * scctx->isc_ntxd[0], M_DEVBUF, M_NOWAIT | M_ZERO))) { | ||||
((pci_subdevice_id == ent->subdevice_id) || | error = ENOMEM; | ||||
(ent->subdevice_id == 0))) { | goto fail; | ||||
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++; | 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_VFTDT(txr->me); | |||||
txr->tx_base = (union ixgbe_adv_tx_desc *)vaddrs[i*ntxqs]; | |||||
txr->tx_paddr = paddrs[i*ntxqs]; | |||||
txr->bytes = 0; | |||||
txr->total_packets = 0; | |||||
} | } | ||||
return (ENXIO); | device_printf(iflib_get_dev(ctx), "allocated for %d queues\n", | ||||
} /* ixv_probe */ | adapter->num_tx_queues); | ||||
return (0); | |||||
fail: | |||||
ixv_if_queues_free(ctx); | |||||
return (error); | |||||
} /* ixv_if_tx_queues_alloc */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_attach - Device initialization routine | * ixv_if_rx_queues_alloc | ||||
************************************************************************/ | |||||
static int | |||||
ixv_if_rx_queues_alloc(if_ctx_t ctx, caddr_t *vaddrs, uint64_t *paddrs, | |||||
int nrxqs, int nrxqsets) | |||||
{ | |||||
struct adapter *adapter = iflib_get_softc(ctx); | |||||
struct ix_rx_queue *que; | |||||
int i, error; | |||||
MPASS(adapter->num_rx_queues == nrxqsets); | |||||
MPASS(nrxqs == 1); | |||||
/* Allocate queue structure memory */ | |||||
adapter->rx_queues = | |||||
(struct ix_rx_queue *)malloc(sizeof(struct ix_rx_queue) * nrxqsets, | |||||
M_DEVBUF, M_NOWAIT | M_ZERO); | |||||
if (!adapter->rx_queues) { | |||||
device_printf(iflib_get_dev(ctx), | |||||
"Unable to allocate TX ring memory\n"); | |||||
error = ENOMEM; | |||||
goto fail; | |||||
} | |||||
for (i = 0, que = adapter->rx_queues; i < nrxqsets; i++, que++) { | |||||
struct rx_ring *rxr = &que->rxr; | |||||
rxr->me = i; | |||||
rxr->adapter = que->adapter = adapter; | |||||
/* get the virtual and physical address of the hw queues */ | |||||
rxr->tail = IXGBE_VFRDT(rxr->me); | |||||
rxr->rx_base = (union ixgbe_adv_rx_desc *)vaddrs[i]; | |||||
rxr->rx_paddr = paddrs[i*nrxqs]; | |||||
rxr->bytes = 0; | |||||
rxr->que = que; | |||||
} | |||||
device_printf(iflib_get_dev(ctx), "allocated for %d rx queues\n", | |||||
adapter->num_rx_queues); | |||||
return (0); | |||||
fail: | |||||
ixv_if_queues_free(ctx); | |||||
return (error); | |||||
} /* ixv_if_rx_queues_alloc */ | |||||
/************************************************************************ | |||||
* ixv_if_queues_free | |||||
************************************************************************/ | |||||
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) | |||||
free(adapter->rx_queues, M_DEVBUF); | |||||
adapter->tx_queues = NULL; | |||||
adapter->rx_queues = NULL; | |||||
} /* ixv_if_queues_free */ | |||||
/************************************************************************ | |||||
* ixv_if_attach_pre - Device initialization routine | |||||
* | * | ||||
* Called when the driver is being loaded. | * Called when the driver is being loaded. | ||||
* Identifies the type of hardware, allocates all resources | * 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) | ||||
{ | { | ||||
struct adapter *adapter; | struct adapter *adapter; | ||||
device_t dev; | |||||
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"); | ||||
/* | |||||
* Make sure BUSMASTER is set, on a VM under | |||||
* KVM it may not be and will break things. | |||||
*/ | |||||
pci_enable_busmaster(dev); | |||||
/* 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; | adapter->hw.back = adapter; | ||||
scctx = adapter->shared = iflib_get_softc_ctx(ctx); | |||||
adapter->media = iflib_get_media(ctx); | |||||
hw = &adapter->hw; | hw = &adapter->hw; | ||||
adapter->init_locked = ixv_init_locked; | |||||
adapter->stop_locked = ixv_stop; | |||||
/* Core Lock Init*/ | |||||
IXGBE_CORE_LOCK_INIT(adapter, device_get_nameunit(dev)); | |||||
/* Do base PCI setup - map BAR0 */ | /* Do base PCI setup - map BAR0 */ | ||||
if (ixv_allocate_pci_resources(adapter)) { | if (ixv_allocate_pci_resources(ctx)) { | ||||
device_printf(dev, "ixv_allocate_pci_resources() failed!\n"); | device_printf(dev, "ixv_allocate_pci_resources() failed!\n"); | ||||
error = ENXIO; | error = ENXIO; | ||||
goto err_out; | goto err_out; | ||||
} | } | ||||
/* 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)), OID_AUTO, "debug", | SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "debug", | ||||
CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixv_sysctl_debug, "I", | CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixv_sysctl_debug, "I", | ||||
"Debug Info"); | "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)), OID_AUTO, | SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, | ||||
"enable_aim", CTLFLAG_RW, &ixv_enable_aim, 1, | "enable_aim", CTLFLAG_RW, &ixv_enable_aim, 1, | ||||
"Interrupt Moderation"); | "Interrupt Moderation"); | ||||
/* Set up the timer callout */ | /* Determine hardware revision */ | ||||
callout_init_mtx(&adapter->timer, &adapter->core_mtx, 0); | ixv_identify_hardware(ctx); | ||||
/* Save off the information about this board */ | |||||
hw->vendor_id = pci_get_vendor(dev); | |||||
hw->device_id = pci_get_device(dev); | |||||
hw->revision_id = pci_get_revid(dev); | |||||
hw->subsystem_vendor_id = pci_get_subvendor(dev); | |||||
hw->subsystem_device_id = pci_get_subdevice(dev); | |||||
/* A subset of set_mac_type */ | |||||
switch (hw->device_id) { | |||||
case IXGBE_DEV_ID_82599_VF: | |||||
hw->mac.type = ixgbe_mac_82599_vf; | |||||
break; | |||||
case IXGBE_DEV_ID_X540_VF: | |||||
hw->mac.type = ixgbe_mac_X540_vf; | |||||
break; | |||||
case IXGBE_DEV_ID_X550_VF: | |||||
hw->mac.type = ixgbe_mac_X550_vf; | |||||
break; | |||||
case IXGBE_DEV_ID_X550EM_X_VF: | |||||
hw->mac.type = ixgbe_mac_X550EM_x_vf; | |||||
break; | |||||
case IXGBE_DEV_ID_X550EM_A_VF: | |||||
hw->mac.type = ixgbe_mac_X550EM_a_vf; | |||||
break; | |||||
default: | |||||
/* Shouldn't get here since probe succeeded */ | |||||
device_printf(dev, "Unknown device ID!\n"); | |||||
error = ENXIO; | |||||
goto err_out; | |||||
break; | |||||
} | |||||
ixv_init_device_features(adapter); | ixv_init_device_features(adapter); | ||||
/* Initialize the shared code */ | /* Initialize the shared code */ | ||||
error = ixgbe_init_ops_vf(hw); | error = ixgbe_init_ops_vf(hw); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "ixgbe_init_ops_vf() failed!\n"); | device_printf(dev, "ixgbe_init_ops_vf() failed!\n"); | ||||
error = EIO; | error = EIO; | ||||
goto err_out; | goto err_out; | ||||
} | } | ||||
/* Setup the mailbox */ | /* Setup the mailbox */ | ||||
ixgbe_init_mbx_params_vf(hw); | ixgbe_init_mbx_params_vf(hw); | ||||
/* Set the right number of segments */ | |||||
adapter->num_segs = IXGBE_82599_SCATTER; | |||||
error = hw->mac.ops.reset_hw(hw); | error = hw->mac.ops.reset_hw(hw); | ||||
if (error == IXGBE_ERR_RESET_FAILED) | if (error == IXGBE_ERR_RESET_FAILED) | ||||
device_printf(dev, "...reset_hw() failure: Reset Failed!\n"); | device_printf(dev, "...reset_hw() failure: Reset Failed!\n"); | ||||
else if (error) | else if (error) | ||||
device_printf(dev, "...reset_hw() failed with error %d\n", | device_printf(dev, "...reset_hw() failed with error %d\n", | ||||
error); | error); | ||||
if (error) { | if (error) { | ||||
error = EIO; | error = EIO; | ||||
Show All 20 Lines | ixv_if_attach_pre(if_ctx_t ctx) | ||||
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)); | bcopy(addr, hw->mac.perm_addr, sizeof(addr)); | ||||
} | } | ||||
/* Register for VLAN events */ | /* Most of the iflib initialization... */ | ||||
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); | |||||
/* Sysctls for limiting the amount of work done in the taskqueues */ | iflib_set_mac(ctx, hw->mac.addr); | ||||
ixv_set_sysctl_value(adapter, "rx_processing_limit", | scctx->isc_txqsizes[0] = | ||||
"max number of rx packets to process", | roundup2(scctx->isc_ntxd[0] * sizeof(union ixgbe_adv_tx_desc) + | ||||
&adapter->rx_process_limit, ixv_rx_process_limit); | sizeof(u32), DBA_ALIGN); | ||||
scctx->isc_rxqsizes[0] = | |||||
roundup2(scctx->isc_nrxd[0] * sizeof(union ixgbe_adv_rx_desc), | |||||
DBA_ALIGN); | |||||
/* XXX */ | |||||
Not Done Inline ActionsMatt says these can be culled to address the XXX https://github.com/mattmacy/networking/commit/bf2207cf58f0fa5c1d3cad382b71480ada2de466#diff-0326730dd8c78abc2aefb006b6ccda74R967 kbowling: Matt says these can be culled to address the XXX https://github. | |||||
Not Done Inline ActionsI'll commit these later today. sbruno: I'll commit these later today. | |||||
scctx->isc_ntxqsets_max = scctx->isc_nrxqsets_max = 1; | |||||
Not Done Inline ActionsNit. Probably wrap this line at 80 cols. :-) sbruno: Nit. Probably wrap this line at 80 cols. :-) | |||||
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; | |||||
ixv_set_sysctl_value(adapter, "tx_processing_limit", | scctx->isc_txrx = &ixgbe_txrx; | ||||
"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 || | * Tell the upper layer(s) we support everything the PF | ||||
ixv_txd < MIN_TXD || ixv_txd > MAX_TXD) { | * driver does except... | ||||
device_printf(dev, "TXD config issue, using default!\n"); | * hardware stats | ||||
adapter->num_tx_desc = DEFAULT_TXD; | * VLAN tag filtering | ||||
} else | * Wake-on-LAN | ||||
adapter->num_tx_desc = ixv_txd; | */ | ||||
scctx->isc_capenable = IXGBE_CAPS; | |||||
scctx->isc_capenable ^= IFCAP_HWSTATS | IFCAP_VLAN_HWFILTER | IFCAP_WOL; | |||||
Not Done Inline ActionsI purged these values from e1000. Do they still do anything in the new ixgbe driver? sbruno: I purged these values from e1000. Do they still do anything in the new ixgbe driver? | |||||
if (((ixv_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || | INIT_DEBUGOUT("ixv_if_attach_pre: end"); | ||||
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; | |||||
/* Setup MSI-X */ | return (0); | ||||
error = ixv_configure_interrupts(adapter); | |||||
if (error) | |||||
goto err_out; | |||||
/* Allocate our TX/RX Queues */ | err_out: | ||||
if (ixgbe_allocate_queues(adapter)) { | ixv_free_pci_resources(ctx); | ||||
device_printf(dev, "ixgbe_allocate_queues() failed!\n"); | |||||
error = ENOMEM; | |||||
goto err_out; | |||||
} | |||||
/* Setup OS specific network interface */ | return (error); | ||||
ixv_setup_interface(dev, adapter); | } /* ixv_if_attach_pre */ | ||||
error = ixv_allocate_msix(adapter); | static int | ||||
ixv_if_attach_post(if_ctx_t ctx) | |||||
{ | |||||
struct adapter *adapter = iflib_get_softc(ctx); | |||||
device_t dev = iflib_get_dev(ctx); | |||||
int error = 0; | |||||
/* Setup OS specific network interface */ | |||||
error = ixv_setup_interface(ctx); | |||||
if (error) { | if (error) { | ||||
device_printf(dev, "ixv_allocate_msix() failed!\n"); | device_printf(dev, "Interface setup failed: %d\n", error); | ||||
goto err_late; | goto end; | ||||
} | } | ||||
/* Do the stats setup */ | /* Do the stats setup */ | ||||
ixv_save_stats(adapter); | ixv_save_stats(adapter); | ||||
ixv_init_stats(adapter); | ixv_init_stats(adapter); | ||||
ixv_add_stats_sysctls(adapter); | ixv_add_stats_sysctls(adapter); | ||||
if (adapter->feat_en & IXGBE_FEATURE_NETMAP) | end: | ||||
ixgbe_netmap_attach(adapter); | return error; | ||||
} /* ixv_if_attach_post */ | |||||
INIT_DEBUGOUT("ixv_attach: end"); | |||||
return (0); | |||||
err_late: | |||||
ixgbe_free_transmit_structures(adapter); | |||||
ixgbe_free_receive_structures(adapter); | |||||
free(adapter->queues, M_DEVBUF); | |||||
err_out: | |||||
ixv_free_pci_resources(adapter); | |||||
IXGBE_CORE_LOCK_DESTROY(adapter); | |||||
return (error); | |||||
} /* ixv_attach */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_detach - Device removal routine | * ixv_detach - Device removal routine | ||||
* | * | ||||
* Called when the driver is being removed. | * Called when the driver is being removed. | ||||
* Stops the adapter and deallocates all the resources | * Stops the adapter and deallocates all the resources | ||||
* that were allocated for driver operation. | * that were allocated for driver operation. | ||||
* | * | ||||
* return 0 on success, positive on failure | * return 0 on success, positive on failure | ||||
************************************************************************/ | ************************************************************************/ | ||||
static int | static int | ||||
ixv_detach(device_t dev) | ixv_if_detach(if_ctx_t ctx) | ||||
{ | { | ||||
struct adapter *adapter = device_get_softc(dev); | |||||
struct ix_queue *que = adapter->queues; | |||||
INIT_DEBUGOUT("ixv_detach: begin"); | INIT_DEBUGOUT("ixv_detach: begin"); | ||||
/* Make sure VLANS are not using driver */ | ixv_free_pci_resources(ctx); | ||||
if (adapter->ifp->if_vlantrunk != NULL) { | |||||
device_printf(dev, "Vlan in use, detach first\n"); | |||||
return (EBUSY); | |||||
} | |||||
ether_ifdetach(adapter->ifp); | return (0); | ||||
IXGBE_CORE_LOCK(adapter); | } /* ixv_if_detach */ | ||||
ixv_stop(adapter); | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
for (int i = 0; i < adapter->num_queues; i++, que++) { | /************************************************************************ | ||||
if (que->tq) { | * ixv_if_mtu_set | ||||
struct tx_ring *txr = que->txr; | ************************************************************************/ | ||||
taskqueue_drain(que->tq, &txr->txq_task); | static int | ||||
taskqueue_drain(que->tq, &que->que_task); | ixv_if_mtu_set(if_ctx_t ctx, uint32_t mtu) | ||||
taskqueue_free(que->tq); | { | ||||
} | struct adapter *adapter = iflib_get_softc(ctx); | ||||
} | struct ifnet *ifp = iflib_get_ifp(ctx); | ||||
int error = 0; | |||||
/* Drain the Mailbox(link) queue */ | IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); | ||||
if (adapter->tq) { | if (mtu > IXGBE_MAX_FRAME_SIZE - IXGBE_MTU_HDR) { | ||||
taskqueue_drain(adapter->tq, &adapter->link_task); | error = EINVAL; | ||||
taskqueue_free(adapter->tq); | } else { | ||||
ifp->if_mtu = mtu; | |||||
adapter->max_frame_size = ifp->if_mtu + IXGBE_MTU_HDR; | |||||
} | } | ||||
/* Unregister VLAN events */ | return error; | ||||
if (adapter->vlan_attach != NULL) | } /* ixv_if_mtu_set */ | ||||
EVENTHANDLER_DEREGISTER(vlan_config, adapter->vlan_attach); | |||||
if (adapter->vlan_detach != NULL) | |||||
EVENTHANDLER_DEREGISTER(vlan_unconfig, adapter->vlan_detach); | |||||
callout_drain(&adapter->timer); | |||||
if (adapter->feat_en & IXGBE_FEATURE_NETMAP) | |||||
netmap_detach(adapter->ifp); | |||||
ixv_free_pci_resources(adapter); | |||||
bus_generic_detach(dev); | |||||
if_free(adapter->ifp); | |||||
ixgbe_free_transmit_structures(adapter); | |||||
ixgbe_free_receive_structures(adapter); | |||||
free(adapter->queues, M_DEVBUF); | |||||
IXGBE_CORE_LOCK_DESTROY(adapter); | |||||
return (0); | |||||
} /* ixv_detach */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_init_locked - Init entry point | * ixv_if_init - Init entry point | ||||
* | * | ||||
* Used in two ways: It is used by the stack as an init entry | * Used in two ways: It is used by the stack as an init entry | ||||
* point in network interface structure. It is also used | * point in network interface structure. It is also used | ||||
* by the driver as a hw/sw initialization routine to get | * by the driver as a hw/sw initialization routine to get | ||||
* to a consistent state. | * to a consistent state. | ||||
* | * | ||||
* return 0 on success, positive on failure | * return 0 on success, positive on failure | ||||
************************************************************************/ | ************************************************************************/ | ||||
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_if_init: begin"); | ||||
mtx_assert(&adapter->core_mtx, MA_OWNED); | |||||
hw->adapter_stopped = FALSE; | hw->adapter_stopped = FALSE; | ||||
hw->mac.ops.stop_adapter(hw); | hw->mac.ops.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. */ | ||||
hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); | hw->mac.ops.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); | |||||
hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, 1); | hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, 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 */ | ||||
hw->mac.ops.reset_hw(hw); | hw->mac.ops.reset_hw(hw); | ||||
error = ixv_negotiate_api(adapter); | error = ixv_negotiate_api(adapter); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Mailbox API negotiation failed in init_locked!\n"); | "Mailbox API negotiation failed in if_init!\n"); | ||||
return; | return; | ||||
} | } | ||||
ixv_initialize_transmit_units(adapter); | ixv_initialize_transmit_units(ctx); | ||||
/* Setup Multicast table */ | /* Setup Multicast table */ | ||||
ixv_set_multi(adapter); | ixv_if_multi_set(ctx); | ||||
/* | /* | ||||
* Determine the correct mbuf pool | * Determine the correct mbuf pool | ||||
* for doing jumbo/headersplit | * for doing jumbo/headersplit | ||||
*/ | */ | ||||
if (ifp->if_mtu > ETHERMTU) | if (ifp->if_mtu > ETHERMTU) | ||||
adapter->rx_mbuf_sz = MJUMPAGESIZE; | adapter->rx_mbuf_sz = MJUMPAGESIZE; | ||||
else | else | ||||
adapter->rx_mbuf_sz = MCLBYTES; | adapter->rx_mbuf_sz = MCLBYTES; | ||||
/* Prepare receive descriptors and buffers */ | |||||
if (ixgbe_setup_receive_structures(adapter)) { | |||||
device_printf(dev, "Could not setup receive structures\n"); | |||||
ixv_stop(adapter); | |||||
return; | |||||
} | |||||
/* Configure RX settings */ | /* Configure RX settings */ | ||||
ixv_initialize_receive_units(adapter); | ixv_initialize_receive_units(ctx); | ||||
/* Set the various hardware offload abilities */ | |||||
ifp->if_hwassist = 0; | |||||
if (ifp->if_capenable & IFCAP_TSO4) | |||||
ifp->if_hwassist |= CSUM_TSO; | |||||
if (ifp->if_capenable & IFCAP_TXCSUM) { | |||||
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | |||||
#if __FreeBSD_version >= 800000 | |||||
ifp->if_hwassist |= CSUM_SCTP; | |||||
#endif | |||||
} | |||||
/* Set up VLAN offload and filter */ | /* Set up VLAN offload and filter */ | ||||
ixv_setup_vlan_support(adapter); | ixv_setup_vlan_support(ctx); | ||||
/* Set up MSI-X routing */ | /* Set up MSI-X routing */ | ||||
ixv_configure_ivars(adapter); | ixv_configure_ivars(adapter); | ||||
/* Set up auto-mask */ | /* Set up auto-mask */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_VTEIAM, IXGBE_EICS_RTX_QUEUE); | IXGBE_WRITE_REG(hw, IXGBE_VTEIAM, IXGBE_EICS_RTX_QUEUE); | ||||
/* Set moderation on the Link interrupt */ | /* Set moderation on the Link interrupt */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_VTEITR(adapter->vector), IXGBE_LINK_ITR); | IXGBE_WRITE_REG(hw, IXGBE_VTEITR(adapter->vector), IXGBE_LINK_ITR); | ||||
/* Stats init */ | /* Stats init */ | ||||
ixv_init_stats(adapter); | ixv_init_stats(adapter); | ||||
/* Config/Enable Link */ | /* Config/Enable Link */ | ||||
hw->mac.ops.check_link(hw, &adapter->link_speed, &adapter->link_up, | hw->mac.ops.check_link(hw, &adapter->link_speed, &adapter->link_up, | ||||
FALSE); | FALSE); | ||||
/* Start watchdog */ | |||||
callout_reset(&adapter->timer, hz, ixv_local_timer, adapter); | |||||
/* And now turn on interrupts */ | /* And now turn on interrupts */ | ||||
ixv_enable_intr(adapter); | ixv_if_enable_intr(ctx); | ||||
/* Now inform the stack we're ready */ | /* Now inform the stack we're ready */ | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | ifp->if_drv_flags |= IFF_DRV_RUNNING; | ||||
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; | ||||
return; | return; | ||||
} /* ixv_init_locked */ | } /* ixv_if_init */ | ||||
/* | /************************************************************************ | ||||
* MSI-X Interrupt Handlers and Tasklets | * ixv_enable_queue | ||||
*/ | ************************************************************************/ | ||||
static inline void | static inline void | ||||
ixv_enable_queue(struct adapter *adapter, u32 vector) | ixv_enable_queue(struct adapter *adapter, u32 vector) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 queue = 1 << vector; | u32 queue = 1 << vector; | ||||
u32 mask; | u32 mask; | ||||
mask = (IXGBE_EIMS_RTX_QUEUE & queue); | mask = (IXGBE_EIMS_RTX_QUEUE & queue); | ||||
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); | IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, mask); | ||||
} /* ixv_enable_queue */ | } /* ixv_enable_queue */ | ||||
/************************************************************************ | |||||
* ixv_disable_queue | |||||
************************************************************************/ | |||||
static inline void | static inline void | ||||
ixv_disable_queue(struct adapter *adapter, u32 vector) | ixv_disable_queue(struct adapter *adapter, u32 vector) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u64 queue = (u64)(1 << vector); | u64 queue = (u64)(1 << vector); | ||||
u32 mask; | u32 mask; | ||||
mask = (IXGBE_EIMS_RTX_QUEUE & queue); | mask = (IXGBE_EIMS_RTX_QUEUE & queue); | ||||
IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, mask); | IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, mask); | ||||
} /* ixv_disable_queue */ | } /* ixv_disable_queue */ | ||||
static inline void | |||||
ixv_rearm_queues(struct adapter *adapter, u64 queues) | |||||
{ | |||||
u32 mask = (IXGBE_EIMS_RTX_QUEUE & queues); | |||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEICS, mask); | |||||
} /* ixv_rearm_queues */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_msix_que - MSI Queue Interrupt Service routine | * ixv_msix_que - MSI-X 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. | |||||
*/ | |||||
if (!ixv_ring_empty(adapter->ifp, txr->br)) | |||||
ixv_start_locked(ifp, txr); | |||||
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_VTEITR(que->msix), | IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEITR(que->msix), | ||||
que->eitr_setting); | que->eitr_setting); | ||||
que->eitr_setting = 0; | que->eitr_setting = 0; | ||||
/* Idle, do nothing */ | #ifdef notyet | ||||
Not Done Inline ActionsWhat is this block being kept around for? sbruno: What is this block being kept around for? | |||||
Not Done Inline ActionsI guess I don't understand why it was originally wrapped. I kept these notyet wrappers from mmacy's original patch for ixgbe, but forgot to ask why they were added. cramerj_intel.com: I guess I don't understand why it was originally wrapped. I kept these notyet wrappers from… | |||||
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, (rxr->bytes / rxr->packets)); | newitr = max(newitr, (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; | ||||
/* Reset state */ | /* Reset state */ | ||||
#ifdef notyet | |||||
Not Done Inline ActionsIs this block the same as above? sbruno: Is this block the same as above? | |||||
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) | |||||
taskqueue_enqueue(que->tq, &que->que_task); | |||||
else /* Re-enable this interrupt */ | |||||
ixv_enable_queue(adapter, que->msix); | |||||
return; | return (FILTER_SCHEDULE_THREAD); | ||||
} /* ixv_msix_que */ | } /* ixv_msix_que */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_msix_mbx | * ixv_msix_mbx | ||||
************************************************************************/ | ************************************************************************/ | ||||
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); | ||||
} /* ixv_msix_mbx */ | } /* ixv_msix_mbx */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_media_status - Media Ioctl callback | * ixv_media_status - Media Ioctl callback | ||||
* | * | ||||
* Called whenever the user queries the status of | * 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_update_link_status(adapter); | |||||
iflib_admin_intr_deferred(ctx); | |||||
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: | ||||
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_10G_T | IFM_FDX; | ifmr->ifm_active |= IFM_10G_T | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_100_FULL: | case IXGBE_LINK_SPEED_100_FULL: | ||||
ifmr->ifm_active |= IFM_100_TX | IFM_FDX; | ifmr->ifm_active |= IFM_100_TX | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_10_FULL: | case IXGBE_LINK_SPEED_10_FULL: | ||||
ifmr->ifm_active |= IFM_10_T | IFM_FDX; | ifmr->ifm_active |= IFM_10_T | IFM_FDX; | ||||
break; | break; | ||||
} | } | ||||
} /* ixv_if_media_status */ | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
return; | |||||
} /* ixv_media_status */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_media_change - Media Ioctl callback | * ixv_if_media_change - Media Ioctl callback | ||||
* | * | ||||
* Called when the user changes speed/duplex using | * Called when the user changes speed/duplex using | ||||
* media/mediopt option with ifconfig. | * media/mediopt option with ifconfig. | ||||
************************************************************************/ | ************************************************************************/ | ||||
static int | static int | ||||
ixv_media_change(struct ifnet *ifp) | ixv_if_media_change(if_ctx_t ctx) | ||||
{ | { | ||||
struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
struct ifmedia *ifm = &adapter->media; | struct ifmedia *ifm = iflib_get_media(ctx); | ||||
INIT_DEBUGOUT("ixv_media_change: begin"); | INIT_DEBUGOUT("ixv_media_change: begin"); | ||||
if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) | if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) | ||||
return (EINVAL); | return (EINVAL); | ||||
switch (IFM_SUBTYPE(ifm->ifm_media)) { | switch (IFM_SUBTYPE(ifm->ifm_media)) { | ||||
case IFM_AUTO: | case IFM_AUTO: | ||||
break; | break; | ||||
default: | default: | ||||
device_printf(adapter->dev, "Only auto media type\n"); | device_printf(adapter->dev, "Only auto media type\n"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
return (0); | return (0); | ||||
} /* ixv_media_change */ | } /* ixv_if_media_change */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_negotiate_api | * ixv_negotiate_api | ||||
* | * | ||||
* Negotiate the Mailbox API with the PF; | * Negotiate the Mailbox API with the PF; | ||||
* start with the most featured API first. | * start with the most featured API first. | ||||
************************************************************************/ | ************************************************************************/ | ||||
Show All 12 Lines | while (mbx_api[i] != ixgbe_mbox_api_unknown) { | ||||
i++; | i++; | ||||
} | } | ||||
return (EINVAL); | return (EINVAL); | ||||
} /* ixv_negotiate_api */ | } /* ixv_negotiate_api */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_set_multi - Multicast Update | * ixv_if_multi_set - Multicast Update | ||||
* | * | ||||
* Called whenever multicast address list is updated. | * Called whenever multicast address list is updated. | ||||
************************************************************************/ | ************************************************************************/ | ||||
static void | static void | ||||
ixv_set_multi(struct adapter *adapter) | ixv_if_multi_set(if_ctx_t ctx) | ||||
{ | { | ||||
u8 mta[MAX_NUM_MULTICAST_ADDRESSES * IXGBE_ETH_LENGTH_OF_ADDRESS]; | u8 mta[MAX_NUM_MULTICAST_ADDRESSES * IXGBE_ETH_LENGTH_OF_ADDRESS]; | ||||
struct adapter *adapter = iflib_get_softc(ctx); | |||||
u8 *update_ptr; | u8 *update_ptr; | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
struct ifnet *ifp = adapter->ifp; | if_t ifp = iflib_get_ifp(ctx); | ||||
int mcnt = 0; | int mcnt = 0; | ||||
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; | ||||
adapter->hw.mac.ops.update_mc_addr_list(&adapter->hw, update_ptr, mcnt, | adapter->hw.mac.ops.update_mc_addr_list(&adapter->hw, update_ptr, mcnt, | ||||
ixv_mc_array_itr, TRUE); | ixv_mc_array_itr, TRUE); | ||||
} /* ixv_if_multi_set */ | |||||
return; | |||||
} /* ixv_set_multi */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_mc_array_itr | * ixv_mc_array_itr | ||||
* | * | ||||
* An iterator function needed by the multicast shared code. | * An iterator function needed by the multicast shared code. | ||||
* It feeds the shared code routine the addresses in the | * It feeds the shared code routine the addresses in the | ||||
* array of ixv_set_multi() one by one. | * array of ixv_set_multi() one by one. | ||||
************************************************************************/ | ************************************************************************/ | ||||
static u8 * | static u8 * | ||||
ixv_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) | ixv_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) | ||||
{ | { | ||||
u8 *addr = *update_ptr; | u8 *addr = *update_ptr; | ||||
u8 *newptr; | u8 *newptr; | ||||
*vmdq = 0; | *vmdq = 0; | ||||
newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; | newptr = addr + IXGBE_ETH_LENGTH_OF_ADDRESS; | ||||
*update_ptr = newptr; | *update_ptr = newptr; | ||||
return addr; | return addr; | ||||
} /* ixv_mc_array_itr */ | } /* ixv_mc_array_itr */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_local_timer - Timer routine | * ixv_if_local_timer - Timer routine | ||||
* | * | ||||
* Checks for link status, updates statistics, | * 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; | if (qid != 0) | ||||
device_t dev = adapter->dev; | |||||
struct ix_queue *que = adapter->queues; | |||||
u64 queues = 0; | |||||
int hung = 0; | |||||
mtx_assert(&adapter->core_mtx, MA_OWNED); | |||||
ixv_check_link(adapter); | |||||
/* Stats Update */ | |||||
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; | return; | ||||
Not Done Inline ActionsCan this be changed to mirror the igb(4) change we made to alleviate some problems with stats counting? https://svnweb.freebsd.org/base/head/sys/dev/e1000/if_em.c?r1=321336&r2=321335&pathrev=321336 sbruno: Can this be changed to mirror the igb(4) change we made to alleviate some problems with stats… | |||||
Not Done Inline ActionsShould this code be moved into ixv_if_update_admin_status() instead of from the timer context? sbruno: Should this code be moved into ixv_if_update_admin_status() instead of from the timer context? | |||||
Not Done Inline ActionsSounds good to me. cramerj_intel.com: Sounds good to me. | |||||
watchdog: | /* Fire off the adminq task */ | ||||
iflib_admin_intr_deferred(ctx); | |||||
} /* ixv_if_local_timer */ | |||||
device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); | |||||
adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | |||||
adapter->watchdog_events++; | |||||
ixv_init_locked(adapter); | |||||
} /* ixv_local_timer */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_update_link_status - Update OS on link state | * ixv_if_update_admin_status - Update OS on link state | ||||
* | * | ||||
* Note: Only updates the OS on the cached link state. | * Note: Only updates the OS on the cached 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); | ||||
adapter->hw.mac.get_link_status = TRUE; | |||||
ixgbe_check_link(&adapter->hw, &adapter->link_speed, &adapter->link_up, | |||||
FALSE); | |||||
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; | /* Stats Update */ | ||||
} /* ixv_update_link_status */ | ixv_update_stats(adapter); | ||||
} /* ixv_if_update_admin_status */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_stop - Stop the hardware | * ixv_if_stop - Stop the hardware | ||||
* | * | ||||
* Disables all traffic on the adapter by issuing a | * Disables all traffic on the adapter by issuing a | ||||
* global reset on the MAC and deallocates TX/RX buffers. | * global reset on the MAC and deallocates TX/RX buffers. | ||||
************************************************************************/ | ************************************************************************/ | ||||
static void | static void | ||||
ixv_stop(void *arg) | ixv_if_stop(if_ctx_t ctx) | ||||
{ | { | ||||
struct ifnet *ifp; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
struct adapter *adapter = arg; | |||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
ifp = adapter->ifp; | |||||
mtx_assert(&adapter->core_mtx, MA_OWNED); | |||||
INIT_DEBUGOUT("ixv_stop: begin\n"); | INIT_DEBUGOUT("ixv_stop: begin\n"); | ||||
ixv_disable_intr(adapter); | |||||
/* Tell the stack that the interface is no longer active */ | ixv_if_disable_intr(ctx); | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); | |||||
hw->mac.ops.reset_hw(hw); | hw->mac.ops.reset_hw(hw); | ||||
adapter->hw.adapter_stopped = FALSE; | adapter->hw.adapter_stopped = FALSE; | ||||
hw->mac.ops.stop_adapter(hw); | hw->mac.ops.stop_adapter(hw); | ||||
callout_stop(&adapter->timer); | |||||
/* Update the stack */ | |||||
adapter->link_up = FALSE; | |||||
ixv_if_update_admin_status(ctx); | |||||
/* reprogram the RAR[0] in case user changed it. */ | /* reprogram the RAR[0] in case user changed it. */ | ||||
hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); | hw->mac.ops.set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); | ||||
} /* ixv_if_stop */ | |||||
return; | |||||
} /* ixv_stop */ | |||||
/************************************************************************ | |||||
* ixv_identify_hardware - Determine hardware revision. | |||||
************************************************************************/ | |||||
static void | |||||
ixv_identify_hardware(if_ctx_t ctx) | |||||
{ | |||||
struct adapter *adapter = iflib_get_softc(ctx); | |||||
device_t dev = iflib_get_dev(ctx); | |||||
struct ixgbe_hw *hw = &adapter->hw; | |||||
/* Save off the information about this board */ | |||||
hw->vendor_id = pci_get_vendor(dev); | |||||
hw->device_id = pci_get_device(dev); | |||||
hw->revision_id = pci_get_revid(dev); | |||||
hw->subsystem_vendor_id = pci_get_subvendor(dev); | |||||
hw->subsystem_device_id = pci_get_subdevice(dev); | |||||
/* We need this to determine device-specific things */ | |||||
ixgbe_set_mac_type(hw); | |||||
} /* ixv_identify_hardware */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_if_msix_intr_assign - Setup MSI-X Interrupt resources and handlers | |||||
************************************************************************/ | |||||
static int | |||||
ixv_if_msix_intr_assign(if_ctx_t ctx, int msix) | |||||
{ | |||||
struct adapter *adapter = iflib_get_softc(ctx); | |||||
device_t dev = iflib_get_dev(ctx); | |||||
struct ix_rx_queue *rx_que = adapter->rx_queues; | |||||
struct ix_tx_queue *tx_que; | |||||
int error, rid, vector = 0; | |||||
char buf[16]; | |||||
for (int i = 0; i < adapter->num_rx_queues; i++, vector++, rx_que++) { | |||||
rid = vector + 1; | |||||
snprintf(buf, sizeof(buf), "rxq%d", i); | |||||
error = iflib_irq_alloc_generic(ctx, &rx_que->que_irq, rid, | |||||
IFLIB_INTR_RX, ixv_msix_que, rx_que, rx_que->rxr.me, buf); | |||||
if (error) { | |||||
device_printf(iflib_get_dev(ctx), | |||||
"Failed to allocate que int %d err: %d", i, error); | |||||
adapter->num_rx_queues = i + 1; | |||||
goto fail; | |||||
} | |||||
rx_que->msix = vector; | |||||
adapter->active_queues |= (u64)(1 << rx_que->msix); | |||||
} | |||||
for (int i = 0; i < adapter->num_tx_queues; i++) { | |||||
snprintf(buf, sizeof(buf), "txq%d", i); | |||||
tx_que = &adapter->tx_queues[i]; | |||||
tx_que->msix = i % adapter->num_rx_queues; | |||||
iflib_softirq_alloc_generic(ctx, rid, IFLIB_INTR_TX, tx_que, | |||||
tx_que->txr.me, buf); | |||||
} | |||||
rid = vector + 1; | |||||
error = iflib_irq_alloc_generic(ctx, &adapter->irq, rid, | |||||
IFLIB_INTR_ADMIN, ixv_msix_mbx, adapter, 0, "aq"); | |||||
if (error) { | |||||
device_printf(iflib_get_dev(ctx), | |||||
"Failed to register admin handler"); | |||||
return (error); | |||||
} | |||||
adapter->vector = vector; | |||||
/* | |||||
* Due to a broken design QEMU will fail to properly | |||||
* enable the guest for MSIX unless the vectors in | |||||
* the table are all set up, so we must rewrite the | |||||
* ENABLE in the MSIX control register again at this | |||||
* point to cause it to successfully initialize us. | |||||
*/ | |||||
if (adapter->hw.mac.type == ixgbe_mac_82599_vf) { | |||||
int msix_ctrl; | |||||
pci_find_cap(dev, PCIY_MSIX, &rid); | |||||
rid += PCIR_MSIX_CTRL; | |||||
msix_ctrl = pci_read_config(dev, rid, 2); | |||||
msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; | |||||
pci_write_config(dev, rid, msix_ctrl, 2); | |||||
} | |||||
return (0); | |||||
fail: | |||||
iflib_irq_free(ctx, &adapter->irq); | |||||
rx_que = adapter->rx_queues; | |||||
for (int i = 0; i < adapter->num_rx_queues; i++, rx_que++) | |||||
iflib_irq_free(ctx, &rx_que->que_irq); | |||||
return (error); | |||||
} /* ixv_if_msix_intr_assign */ | |||||
/************************************************************************ | |||||
* ixv_allocate_pci_resources | * ixv_allocate_pci_resources | ||||
************************************************************************/ | ************************************************************************/ | ||||
static int | static int | ||||
ixv_allocate_pci_resources(struct adapter *adapter) | ixv_allocate_pci_resources(if_ctx_t ctx) | ||||
{ | { | ||||
device_t dev = adapter->dev; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
device_t dev = iflib_get_dev(ctx); | |||||
int rid; | int rid; | ||||
rid = PCIR_BAR(0); | rid = PCIR_BAR(0); | ||||
adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | ||||
RF_ACTIVE); | 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 = rman_get_bustag(adapter->pci_mem); | adapter->osdep.mem_bus_space_tag = 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 */ | |||||
adapter->num_queues = ixv_num_queues; | |||||
return (0); | return (0); | ||||
Not Done Inline ActionsIFLIB allows num_rx_queues and num_tx_queues to be configured independently. It appears this is ignoring the iflib value and using the old style hw.ixv.num_queues value sbruno: IFLIB allows num_rx_queues and num_tx_queues to be configured independently. It appears this… | |||||
Not Done Inline ActionsIf you think that's strange, consider the fact that we were setting isc_max_[rt]xqsets in attach_pre, but those values aren't used anywhere in iflib.c! What was the intention of isc_max_[rt]xqsets? How were they supposed to be different from isc_n[rt]xqsets_max? Regardless, I've adjusted it to mimic e1000. cramerj_intel.com: If you think that's strange, consider the fact that we were setting isc_max_[rt]xqsets in… | |||||
} /* ixv_allocate_pci_resources */ | } /* ixv_allocate_pci_resources */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_free_pci_resources | * ixv_free_pci_resources | ||||
************************************************************************/ | ************************************************************************/ | ||||
static void | static void | ||||
ixv_free_pci_resources(struct adapter * adapter) | ixv_free_pci_resources(if_ctx_t ctx) | ||||
{ | { | ||||
Not Done Inline ActionsIt looks like we reserve rid == 1 and vector = 0 here, but the actual assignment of the admin IRQ uses rid = (max rx_rid + max tx_rid) after queue assignment is done at line 1108. I suspect just deleting these two lines is "correct"? sbruno: It looks like we reserve rid == 1 and vector = 0 here, but the actual assignment of the admin… | |||||
Not Done Inline ActionsYep. cramerj_intel.com: Yep. | |||||
struct ix_queue *que = adapter->queues; | struct adapter *adapter = iflib_get_softc(ctx); | ||||
device_t dev = adapter->dev; | struct ix_rx_queue *que = adapter->rx_queues; | ||||
int rid, memrid; | device_t dev = iflib_get_dev(ctx); | ||||
memrid = PCIR_BAR(MSIX_82598_BAR); | /* Release all msix queue resources */ | ||||
if (adapter->intr_type == IFLIB_INTR_MSIX) | |||||
iflib_irq_free(ctx, &adapter->irq); | |||||
/* | if (que != NULL) { | ||||
* There is a slight possibility of a failure mode | for (int i = 0; i < adapter->num_rx_queues; i++, que++) { | ||||
* in attach that will result in entering this function | iflib_irq_free(ctx, &que->que_irq); | ||||
* before interrupt resources have been initialized, and | |||||
* in that case we do not want to execute the loops below | |||||
* We can detect this reliably by the state of the adapter | |||||
* res pointer. | |||||
*/ | |||||
if (adapter->res == NULL) | |||||
goto mem; | |||||
/* | |||||
* Release all msix queue resources: | |||||
*/ | |||||
for (int i = 0; i < adapter->num_queues; i++, que++) { | |||||
rid = que->msix + 1; | |||||
if (que->tag != NULL) { | |||||
bus_teardown_intr(dev, que->res, que->tag); | |||||
que->tag = NULL; | |||||
} | } | ||||
if (que->res != NULL) | |||||
bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); | |||||
} | } | ||||
/* Clean the Legacy or Link interrupt last */ | |||||
/* Clean the Mailbox interrupt last */ | |||||
rid = adapter->vector + 1; | |||||
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: | |||||
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, PCIR_BAR(0), | bus_release_resource(dev, SYS_RES_MEMORY, | ||||
adapter->pci_mem); | PCIR_BAR(0), adapter->pci_mem); | ||||
return; | |||||
} /* ixv_free_pci_resources */ | } /* ixv_free_pci_resources */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_setup_interface | * ixv_setup_interface | ||||
* | * | ||||
* 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_setgetcounterfn(ifp, ixv_get_counter); | |||||
/* TSO parameters */ | |||||
ifp->if_hw_tsomax = 65518; | |||||
ifp->if_hw_tsomaxsegcount = IXGBE_82599_SCATTER; | |||||
ifp->if_hw_tsomaxsegsize = 2048; | |||||
if (adapter->feat_en & IXGBE_FEATURE_LEGACY_TX) { | |||||
ifp->if_start = ixgbe_legacy_start; | |||||
ixv_start_locked = ixgbe_legacy_start_locked; | |||||
ixv_ring_empty = ixgbe_legacy_ring_empty; | |||||
} else { | |||||
ifp->if_transmit = ixgbe_mq_start; | |||||
ifp->if_qflush = ixgbe_qflush; | |||||
ixv_start_locked = ixgbe_mq_start_locked; | |||||
ixv_ring_empty = drbr_empty; | |||||
} | |||||
IFQ_SET_MAXLEN(&ifp->if_snd, 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 = ifp->if_mtu + IXGBE_MTU_HDR; | ||||
ifmedia_add(adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); | |||||
ifmedia_set(adapter->media, IFM_ETHER | IFM_AUTO); | |||||
/* | return 0; | ||||
* Tell the upper layer(s) we support long frames. | |||||
*/ | |||||
ifp->if_hdrlen = sizeof(struct ether_vlan_header); | |||||
/* Set capability flags */ | |||||
ifp->if_capabilities |= IFCAP_HWCSUM | |||||
| IFCAP_HWCSUM_IPV6 | |||||
| IFCAP_TSO | |||||
| IFCAP_LRO | |||||
| IFCAP_VLAN_HWTAGGING | |||||
| IFCAP_VLAN_HWTSO | |||||
| IFCAP_VLAN_HWCSUM | |||||
| IFCAP_JUMBO_MTU | |||||
| IFCAP_VLAN_MTU; | |||||
/* Enable the above capabilities by default */ | |||||
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; | |||||
} /* ixv_setup_interface */ | } /* ixv_setup_interface */ | ||||
/************************************************************************ | |||||
* ixv_if_get_counter | |||||
************************************************************************/ | |||||
static uint64_t | |||||
ixv_if_get_counter(if_ctx_t ctx, ift_counter cnt) | |||||
{ | |||||
struct adapter *adapter = iflib_get_softc(ctx); | |||||
if_t ifp = iflib_get_ifp(ctx); | |||||
switch (cnt) { | |||||
case IFCOUNTER_IPACKETS: | |||||
return (adapter->ipackets); | |||||
case IFCOUNTER_OPACKETS: | |||||
return (adapter->opackets); | |||||
case IFCOUNTER_IBYTES: | |||||
return (adapter->ibytes); | |||||
case IFCOUNTER_OBYTES: | |||||
return (adapter->obytes); | |||||
case IFCOUNTER_IMCASTS: | |||||
return (adapter->imcasts); | |||||
default: | |||||
return (if_get_counter_default(ifp, cnt)); | |||||
} | |||||
} /* ixv_if_get_counter */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_initialize_transmit_units - Enable transmit unit. | * ixv_initialize_transmit_units - 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); | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
if_softc_ctx_t scctx = adapter->shared; | |||||
struct ix_tx_queue *que = adapter->tx_queues; | |||||
int i; | |||||
for (i = 0; i < adapter->num_tx_queues; i++, que++) { | |||||
for (int i = 0; i < adapter->num_queues; i++, txr++) { | struct tx_ring *txr = &que->txr; | ||||
u64 tdba = txr->txdma.dma_paddr; | u64 tdba = txr->tx_paddr; | ||||
u32 txctrl, txdctl; | u32 txctrl, txdctl; | ||||
int j = txr->me; | |||||
/* Set WTHRESH to 8, burst writeback */ | /* Set WTHRESH to 8, burst writeback */ | ||||
txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(i)); | txdctl = IXGBE_READ_REG(hw, IXGBE_VFTXDCTL(j)); | ||||
txdctl |= (8 << 16); | txdctl |= (8 << 16); | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(i), txdctl); | IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(j), txdctl); | ||||
/* Set the HW Tx Head and Tail indices */ | /* Set the HW Tx Head and Tail indices */ | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDH(i), 0); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDH(j), 0); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDT(i), 0); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_VFTDT(j), 0); | ||||
/* Set Tx Tail register */ | /* Set Tx Tail register */ | ||||
txr->tail = IXGBE_VFTDT(i); | txr->tail = IXGBE_VFTDT(j); | ||||
txr->tx_rs_cidx = txr->tx_rs_pidx = txr->tx_cidx_processed = 0; | |||||
for (int k = 0; k < scctx->isc_ntxd[0]; k++) | |||||
txr->tx_rsq[k] = QIDX_INVALID; | |||||
/* Set Ring parameters */ | /* Set Ring parameters */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFTDBAL(i), | IXGBE_WRITE_REG(hw, IXGBE_VFTDBAL(j), | ||||
(tdba & 0x00000000ffffffffULL)); | (tdba & 0x00000000ffffffffULL)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFTDBAH(i), (tdba >> 32)); | IXGBE_WRITE_REG(hw, IXGBE_VFTDBAH(j), (tdba >> 32)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(i), | IXGBE_WRITE_REG(hw, IXGBE_VFTDLEN(j), | ||||
adapter->num_tx_desc * sizeof(struct ixgbe_legacy_tx_desc)); | scctx->isc_ntxd[0] * sizeof(struct ixgbe_legacy_tx_desc)); | ||||
txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(i)); | txctrl = IXGBE_READ_REG(hw, IXGBE_VFDCA_TXCTRL(j)); | ||||
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_transmit_units */ | } /* ixv_initialize_transmit_units */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_initialize_rss_mapping | * ixv_initialize_rss_mapping | ||||
************************************************************************/ | ************************************************************************/ | ||||
static void | static void | ||||
ixv_initialize_rss_mapping(struct adapter *adapter) | ixv_initialize_rss_mapping(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 reta = 0, mrqc, rss_key[10]; | u32 reta = 0, mrqc, rss_key[10]; | ||||
Show All 10 Lines | ixv_initialize_rss_mapping(struct adapter *adapter) | ||||
} | } | ||||
/* Now fill out hash function seeds */ | /* Now fill out hash function seeds */ | ||||
for (i = 0; i < 10; i++) | for (i = 0; i < 10; i++) | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]); | IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]); | ||||
/* Set up the redirection table */ | /* Set up the redirection table */ | ||||
for (i = 0, j = 0; i < 64; i++, j++) { | for (i = 0, j = 0; i < 64; i++, j++) { | ||||
if (j == adapter->num_queues) | if (j == adapter->num_rx_queues) | ||||
j = 0; | j = 0; | ||||
if (adapter->feat_en & IXGBE_FEATURE_RSS) { | if (adapter->feat_en & IXGBE_FEATURE_RSS) { | ||||
/* | /* | ||||
* Fetch the RSS bucket id for the given indirection | * Fetch the RSS bucket id for the given indirection | ||||
* entry. Cap it at the number of configured buckets | * entry. Cap it at the number of configured buckets | ||||
* (which is num_queues.) | * (which is num_rx_queues.) | ||||
*/ | */ | ||||
queue_id = rss_get_indirection_to_bucket(i); | queue_id = rss_get_indirection_to_bucket(i); | ||||
queue_id = queue_id % adapter->num_queues; | queue_id = queue_id % adapter->num_rx_queues; | ||||
} else | } else | ||||
queue_id = j; | queue_id = j; | ||||
/* | /* | ||||
* The low 8 bits are for hash value (n+0); | * The low 8 bits are for hash value (n+0); | ||||
* The next 8 bits are for hash value (n+1), etc. | * The next 8 bits are for hash value (n+1), etc. | ||||
*/ | */ | ||||
reta >>= 8; | reta >>= 8; | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | ixv_initialize_rss_mapping(struct adapter *adapter) | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFMRQC, mrqc); | IXGBE_WRITE_REG(hw, IXGBE_VFMRQC, mrqc); | ||||
} /* ixv_initialize_rss_mapping */ | } /* ixv_initialize_rss_mapping */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_initialize_receive_units - Setup receive registers and features. | * ixv_initialize_receive_units - Setup receive registers and features. | ||||
************************************************************************/ | ************************************************************************/ | ||||
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 | psrtype = IXGBE_PSRTYPE_TCPHDR | ||||
| IXGBE_PSRTYPE_UDPHDR | | IXGBE_PSRTYPE_UDPHDR | ||||
| IXGBE_PSRTYPE_IPV4HDR | | IXGBE_PSRTYPE_IPV4HDR | ||||
| IXGBE_PSRTYPE_IPV6HDR | | IXGBE_PSRTYPE_IPV6HDR | ||||
| IXGBE_PSRTYPE_L2HDR; | | IXGBE_PSRTYPE_L2HDR; | ||||
if (adapter->num_queues > 1) | if (adapter->num_rx_queues > 1) | ||||
psrtype |= 1 << 29; | 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 */ | ||||
if (ixgbevf_rlpml_set_vf(hw, adapter->max_frame_size) != 0) { | if (ixgbevf_rlpml_set_vf(hw, adapter->max_frame_size) != 0) { | ||||
device_printf(adapter->dev, "There is a problem with the PF setup. It is likely the receive unit for this VF will not function correctly.\n"); | device_printf(adapter->dev, "There is a problem with the PF setup. It is likely the receive unit for this VF will not function correctly.\n"); | ||||
} | } | ||||
scctx = adapter->shared; | |||||
for (int i = 0; i < adapter->num_queues; i++, rxr++) { | for (int i = 0; i < adapter->num_rx_queues; i++, que++) { | ||||
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), (rdba >> 32)); | IXGBE_WRITE_REG(hw, IXGBE_VFRDBAH(j), (rdba >> 32)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(i), | IXGBE_WRITE_REG(hw, IXGBE_VFRDLEN(j), | ||||
adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); | scctx->isc_nrxd[0] * 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; | ||||
msec_delay(1); | msec_delay(1); | ||||
} | } | ||||
wmb(); | wmb(); | ||||
/* Set the Tail Pointer */ | /* Set the Tail Pointer */ | ||||
#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. | ||||
*/ | */ | ||||
#ifdef DEV_NETMAP | if (ifp->if_capenable & IFCAP_NETMAP) { | ||||
if ((adapter->feat_en & IXGBE_FEATURE_NETMAP) && | struct netmap_adapter *na = NA(ifp); | ||||
(ifp->if_capenable & IFCAP_NETMAP)) { | struct netmap_kring *kring = &na->rx_rings[j]; | ||||
struct netmap_adapter *na = NA(adapter->ifp); | |||||
struct netmap_kring *kring = &na->rx_rings[i]; | |||||
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); | ixv_initialize_rss_mapping(adapter); | ||||
if (adapter->num_queues > 1) { | if (adapter->num_rx_queues > 1) { | ||||
/* RSS and RX IPP Checksum are mutually exclusive */ | /* RSS and RX IPP Checksum are mutually exclusive */ | ||||
rxcsum |= IXGBE_RXCSUM_PCSD; | 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; | |||||
} /* ixv_initialize_receive_units */ | } /* ixv_initialize_receive_units */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_setup_vlan_support | * ixv_setup_vlan_support | ||||
************************************************************************/ | ************************************************************************/ | ||||
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; | ||||
/* | /* | ||||
* We get here thru init_locked, meaning | * We get here thru if_init, 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. | ||||
*/ | */ | ||||
adapter->rx_rings[i].vtag_strip = TRUE; | adapter->rx_queues[i].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) | ||||
Show All 14 Lines | for (int j = 0; j < 32; j++) { | ||||
if (++retry > 5) | if (++retry > 5) | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} /* ixv_setup_vlan_support */ | } /* ixv_setup_vlan_support */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_register_vlan | * ixv_if_register_vlan | ||||
* | * | ||||
* Run via a vlan config EVENT, it enables us to use the | * Run via a vlan config EVENT, it enables us to use the | ||||
* HW Filter table since we can get the vlan id. This just | * HW Filter table since we can get the vlan id. This just | ||||
* creates the entry in the soft version of the VFTA, init | * creates the entry in the soft version of the VFTA, init | ||||
* will repopulate the real table. | * will 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_if_register_vlan */ | ||||
ixv_init_locked(adapter); | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
} /* ixv_register_vlan */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_unregister_vlan | * ixv_if_unregister_vlan | ||||
* | * | ||||
* Run via a vlan unconfig EVENT, remove our entry | * Run via a vlan 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_if_unregister_vlan */ | ||||
ixv_init_locked(adapter); | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
} /* ixv_unregister_vlan */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_enable_intr | * ixv_if_enable_intr | ||||
************************************************************************/ | ************************************************************************/ | ||||
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); | ||||
} /* ixv_if_enable_intr */ | |||||
return; | |||||
} /* ixv_enable_intr */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_disable_intr | * ixv_if_disable_intr | ||||
************************************************************************/ | ************************************************************************/ | ||||
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); | ||||
} /* ixv_if_disable_intr */ | |||||
return; | /************************************************************************ | ||||
} /* ixv_disable_intr */ | * ixv_if_rx_queue_intr_enable | ||||
************************************************************************/ | |||||
static int | |||||
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); | |||||
} /* ixv_if_rx_queue_intr_enable */ | |||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_set_ivar | * ixv_set_ivar | ||||
* | * | ||||
* Setup the correct IVAR register for a particular MSI-X interrupt | * Setup the correct IVAR register for a particular MSI-X interrupt | ||||
* - entry is the register array entry | * - entry is the register array entry | ||||
* - vector is the MSI-X vector for this queue | * - vector is the MSI-X vector for this queue | ||||
* - type is RX/TX/MISC | * - type is RX/TX/MISC | ||||
************************************************************************/ | ************************************************************************/ | ||||
Show All 20 Lines | |||||
} /* ixv_set_ivar */ | } /* ixv_set_ivar */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_configure_ivars | * ixv_configure_ivars | ||||
************************************************************************/ | ************************************************************************/ | ||||
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_VTEITR(que->msix), | IXGBE_WRITE_REG(&adapter->hw, IXGBE_VTEITR(que->msix), | ||||
IXGBE_EITR_DEFAULT); | IXGBE_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); | ||||
} /* ixv_configure_ivars */ | } /* ixv_configure_ivars */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_get_counter | |||||
************************************************************************/ | |||||
static uint64_t | |||||
ixv_get_counter(struct ifnet *ifp, ift_counter cnt) | |||||
{ | |||||
struct adapter *adapter; | |||||
adapter = if_getsoftc(ifp); | |||||
switch (cnt) { | |||||
case IFCOUNTER_IPACKETS: | |||||
return (adapter->ipackets); | |||||
case IFCOUNTER_OPACKETS: | |||||
return (adapter->opackets); | |||||
case IFCOUNTER_IBYTES: | |||||
return (adapter->ibytes); | |||||
case IFCOUNTER_OBYTES: | |||||
return (adapter->obytes); | |||||
case IFCOUNTER_IMCASTS: | |||||
return (adapter->imcasts); | |||||
default: | |||||
return (if_get_counter_default(ifp, cnt)); | |||||
} | |||||
} /* ixv_get_counter */ | |||||
/************************************************************************ | |||||
* ixv_save_stats | * ixv_save_stats | ||||
* | * | ||||
* The VF stats registers never have a truly virgin | * 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 | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | |||||
* ixv_update_stats - Update the board statistics counters. | * ixv_update_stats - Update the board statistics counters. | ||||
************************************************************************/ | ************************************************************************/ | ||||
void | void | ||||
ixv_update_stats(struct adapter *adapter) | ixv_update_stats(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
struct ixgbevf_hw_stats *stats = &adapter->stats.vf; | struct ixgbevf_hw_stats *stats = &adapter->stats.vf; | ||||
UPDATE_STAT_32(IXGBE_VFGPRC, adapter->stats.vf.last_vfgprc, | UPDATE_STAT_32(IXGBE_VFGPRC, adapter->stats.vf.last_vfgprc, | ||||
adapter->stats.vf.vfgprc); | adapter->stats.vf.vfgprc); | ||||
UPDATE_STAT_32(IXGBE_VFGPTC, adapter->stats.vf.last_vfgptc, | UPDATE_STAT_32(IXGBE_VFGPTC, adapter->stats.vf.last_vfgptc, | ||||
adapter->stats.vf.vfgptc); | adapter->stats.vf.vfgptc); | ||||
UPDATE_STAT_36(IXGBE_VFGORC_LSB, IXGBE_VFGORC_MSB, | UPDATE_STAT_36(IXGBE_VFGORC_LSB, IXGBE_VFGORC_MSB, | ||||
adapter->stats.vf.last_vfgorc, adapter->stats.vf.vfgorc); | adapter->stats.vf.last_vfgorc, adapter->stats.vf.vfgorc); | ||||
UPDATE_STAT_36(IXGBE_VFGOTC_LSB, IXGBE_VFGOTC_MSB, | UPDATE_STAT_36(IXGBE_VFGOTC_LSB, IXGBE_VFGOTC_MSB, | ||||
adapter->stats.vf.last_vfgotc, adapter->stats.vf.vfgotc); | adapter->stats.vf.last_vfgotc, adapter->stats.vf.vfgotc); | ||||
UPDATE_STAT_32(IXGBE_VFMPRC, adapter->stats.vf.last_vfmprc, | UPDATE_STAT_32(IXGBE_VFMPRC, adapter->stats.vf.last_vfmprc, | ||||
adapter->stats.vf.vfmprc); | adapter->stats.vf.vfmprc); | ||||
/* Fill out the OS statistics structure */ | /* Fill out the OS statistics structure */ | ||||
IXGBE_SET_IPACKETS(adapter, stats->vfgprc); | IXGBE_SET_IPACKETS(adapter, stats->vfgprc); | ||||
IXGBE_SET_OPACKETS(adapter, stats->vfgptc); | IXGBE_SET_OPACKETS(adapter, stats->vfgptc); | ||||
IXGBE_SET_IBYTES(adapter, stats->vfgorc); | IXGBE_SET_IBYTES(adapter, stats->vfgorc); | ||||
IXGBE_SET_OBYTES(adapter, stats->vfgotc); | IXGBE_SET_OBYTES(adapter, stats->vfgotc); | ||||
IXGBE_SET_IMCASTS(adapter, stats->vfmprc); | IXGBE_SET_IMCASTS(adapter, stats->vfmprc); | ||||
} /* ixv_update_stats */ | } /* ixv_update_stats */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_add_stats_sysctls - Add statistic sysctls for the VF. | * ixv_add_stats_sysctls - 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 tx_ring *txr = adapter->tx_rings; | struct ix_tx_queue *tx_que = adapter->tx_queues; | ||||
struct rx_ring *rxr = adapter->rx_rings; | struct ix_rx_queue *rx_que = adapter->rx_queues; | ||||
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); | struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); | ||||
struct sysctl_oid *tree = device_get_sysctl_tree(dev); | struct sysctl_oid *tree = device_get_sysctl_tree(dev); | ||||
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); | struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); | ||||
struct ixgbevf_hw_stats *stats = &adapter->stats.vf; | struct ixgbevf_hw_stats *stats = &adapter->stats.vf; | ||||
struct sysctl_oid *stat_node, *queue_node; | struct sysctl_oid *stat_node, *queue_node; | ||||
struct sysctl_oid_list *stat_list, *queue_list; | struct sysctl_oid_list *stat_list, *queue_list; | ||||
#define QUEUE_NAME_LEN 32 | #define QUEUE_NAME_LEN 32 | ||||
char namebuf[QUEUE_NAME_LEN]; | char namebuf[QUEUE_NAME_LEN]; | ||||
/* Driver Statistics */ | /* Driver Statistics */ | ||||
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", | |||||
CTLFLAG_RD, &adapter->dropped_pkts, "Driver dropped packets"); | |||||
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", | |||||
CTLFLAG_RD, &adapter->mbuf_defrag_failed, "m_defrag() failed"); | |||||
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", | SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", | ||||
CTLFLAG_RD, &adapter->watchdog_events, "Watchdog timeouts"); | CTLFLAG_RD, &adapter->watchdog_events, "Watchdog timeouts"); | ||||
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", | SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", | ||||
CTLFLAG_RD, &adapter->link_irq, "Link MSI-X IRQ Handled"); | CTLFLAG_RD, &adapter->link_irq, "Link MSI-X IRQ Handled"); | ||||
for (int i = 0; i < adapter->num_queues; i++, txr++) { | for (int i = 0; i < adapter->num_tx_queues; i++, tx_que++) { | ||||
struct tx_ring *txr = &tx_que->txr; | |||||
snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); | snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); | ||||
queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, | queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, | ||||
CTLFLAG_RD, NULL, "Queue Name"); | CTLFLAG_RD, NULL, "Queue Name"); | ||||
queue_list = SYSCTL_CHILDREN(queue_node); | queue_list = SYSCTL_CHILDREN(queue_node); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", | SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", | ||||
CTLFLAG_RD, &(adapter->queues[i].irqs), "IRQs on queue"); | CTLFLAG_RD, &(txr->tso_tx), "TSO Packets"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", | |||||
CTLFLAG_RD, &(txr->no_tx_dma_setup), | |||||
"Driver Tx DMA failure in Tx"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_no_desc", | |||||
CTLFLAG_RD, &(txr->no_desc_avail), | |||||
"Not-enough-descriptors count: TX"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", | ||||
CTLFLAG_RD, &(txr->total_packets), "TX Packets"); | CTLFLAG_RD, &(txr->total_packets), "TX Packets"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", | |||||
CTLFLAG_RD, &(txr->br->br_drops), | |||||
"Packets dropped in buf_ring"); | |||||
} | } | ||||
for (int i = 0; i < adapter->num_queues; i++, rxr++) { | for (int i = 0; i < adapter->num_rx_queues; i++, rx_que++) { | ||||
struct rx_ring *rxr = &rx_que->rxr; | |||||
snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); | snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); | ||||
queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, | queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, | ||||
CTLFLAG_RD, NULL, "Queue Name"); | CTLFLAG_RD, NULL, "Queue Name"); | ||||
queue_list = SYSCTL_CHILDREN(queue_node); | queue_list = SYSCTL_CHILDREN(queue_node); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", | |||||
CTLFLAG_RD, &(rx_que->irqs), "IRQs on queue"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", | ||||
CTLFLAG_RD, &(rxr->rx_packets), "RX packets"); | CTLFLAG_RD, &(rxr->rx_packets), "RX packets"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", | ||||
CTLFLAG_RD, &(rxr->rx_bytes), "RX bytes"); | CTLFLAG_RD, &(rxr->rx_bytes), "RX bytes"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_discarded", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_discarded", | ||||
CTLFLAG_RD, &(rxr->rx_discarded), "Discarded RX packets"); | CTLFLAG_RD, &(rxr->rx_discarded), "Discarded RX packets"); | ||||
} | } | ||||
Show All 33 Lines | |||||
* Provides a way to take a look at important statistics | * 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++) { | |||||
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); | device_printf(dev, "MBX IRQ Handled: %lu\n", (long)adapter->link_irq); | ||||
} /* ixv_print_debug_info */ | } /* ixv_print_debug_info */ | ||||
/************************************************************************ | /************************************************************************ | ||||
* ixv_sysctl_debug | * ixv_sysctl_debug | ||||
************************************************************************/ | ************************************************************************/ | ||||
static int | static int | ||||
ixv_sysctl_debug(SYSCTL_HANDLER_ARGS) | ixv_sysctl_debug(SYSCTL_HANDLER_ARGS) | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | ixv_init_device_features(struct adapter *adapter) | ||||
if (adapter->feat_cap & IXGBE_FEATURE_NETMAP) | if (adapter->feat_cap & IXGBE_FEATURE_NETMAP) | ||||
adapter->feat_en |= IXGBE_FEATURE_NETMAP; | adapter->feat_en |= IXGBE_FEATURE_NETMAP; | ||||
/* Receive-Side Scaling (RSS) */ | /* Receive-Side Scaling (RSS) */ | ||||
if (adapter->feat_cap & IXGBE_FEATURE_RSS) | if (adapter->feat_cap & IXGBE_FEATURE_RSS) | ||||
adapter->feat_en |= IXGBE_FEATURE_RSS; | adapter->feat_en |= IXGBE_FEATURE_RSS; | ||||
/* Needs advanced context descriptor regardless of offloads req'd */ | /* Needs advanced context descriptor regardless of offloads req'd */ | ||||
if (adapter->feat_cap & IXGBE_FEATURE_NEEDS_CTXD) | if (adapter->feat_cap & IXGBE_FEATURE_NEEDS_CTXD) | ||||
adapter->feat_en |= IXGBE_FEATURE_NEEDS_CTXD; | adapter->feat_en |= IXGBE_FEATURE_NEEDS_CTXD; | ||||
/* Enabled via sysctl... */ | |||||
/* Legacy (single queue) transmit */ | |||||
if ((adapter->feat_cap & IXGBE_FEATURE_LEGACY_TX) && | |||||
ixv_enable_legacy_tx) | |||||
adapter->feat_en |= IXGBE_FEATURE_LEGACY_TX; | |||||
} /* ixv_init_device_features */ | } /* ixv_init_device_features */ | ||||
/************************************************************************ | |||||
* ixv_shutdown - Shutdown entry point | |||||
************************************************************************/ | |||||
static int | |||||
ixv_shutdown(device_t dev) | |||||
{ | |||||
struct adapter *adapter = device_get_softc(dev); | |||||
IXGBE_CORE_LOCK(adapter); | |||||
ixv_stop(adapter); | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
return (0); | |||||
} /* ixv_shutdown */ | |||||
/************************************************************************ | |||||
* ixv_ioctl - Ioctl entry point | |||||
* | |||||
* Called when the user wants to configure the interface. | |||||
* | |||||
* return 0 on success, positive on failure | |||||
************************************************************************/ | |||||
static int | |||||
ixv_ioctl(struct ifnet *ifp, u_long command, caddr_t data) | |||||
{ | |||||
struct adapter *adapter = ifp->if_softc; | |||||
struct ifreq *ifr = (struct ifreq *)data; | |||||
#if defined(INET) || defined(INET6) | |||||
struct ifaddr *ifa = (struct ifaddr *)data; | |||||
bool avoid_reset = FALSE; | |||||
#endif | |||||
int error = 0; | |||||
switch (command) { | |||||
case SIOCSIFADDR: | |||||
#ifdef INET | |||||
if (ifa->ifa_addr->sa_family == AF_INET) | |||||
avoid_reset = TRUE; | |||||
#endif | |||||
#ifdef INET6 | |||||
if (ifa->ifa_addr->sa_family == AF_INET6) | |||||
avoid_reset = TRUE; | |||||
#endif | |||||
#if defined(INET) || defined(INET6) | |||||
/* | |||||
* Calling init results in link renegotiation, | |||||
* so we avoid doing it when possible. | |||||
*/ | |||||
if (avoid_reset) { | |||||
ifp->if_flags |= IFF_UP; | |||||
if (!(ifp->if_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)"); | |||||
if (ifr->ifr_mtu > IXGBE_MAX_MTU) { | |||||
error = EINVAL; | |||||
} else { | |||||
IXGBE_CORE_LOCK(adapter); | |||||
ifp->if_mtu = ifr->ifr_mtu; | |||||
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; | |||||
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); | |||||
} /* ixv_ioctl */ | |||||
/************************************************************************ | |||||
* ixv_init | |||||
************************************************************************/ | |||||
static void | |||||
ixv_init(void *arg) | |||||
{ | |||||
struct adapter *adapter = arg; | |||||
IXGBE_CORE_LOCK(adapter); | |||||
ixv_init_locked(adapter); | |||||
IXGBE_CORE_UNLOCK(adapter); | |||||
return; | |||||
} /* ixv_init */ | |||||
/************************************************************************ | |||||
* ixv_handle_que | |||||
************************************************************************/ | |||||
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 (!ixv_ring_empty(ifp, txr->br)) | |||||
ixv_start_locked(ifp, txr); | |||||
IXGBE_TX_UNLOCK(txr); | |||||
if (more) { | |||||
taskqueue_enqueue(que->tq, &que->que_task); | |||||
return; | |||||
} | |||||
} | |||||
/* Re-enable this interrupt */ | |||||
ixv_enable_queue(adapter, que->msix); | |||||
return; | |||||
} /* ixv_handle_que */ | |||||
/************************************************************************ | |||||
* ixv_allocate_msix - Setup MSI-X Interrupt resources and handlers | |||||
************************************************************************/ | |||||
static int | |||||
ixv_allocate_msix(struct adapter *adapter) | |||||
{ | |||||
device_t dev = adapter->dev; | |||||
struct ix_queue *que = adapter->queues; | |||||
struct tx_ring *txr = adapter->tx_rings; | |||||
int error, msix_ctrl, rid, vector = 0; | |||||
for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { | |||||
rid = vector + 1; | |||||
que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | |||||
RF_SHAREABLE | RF_ACTIVE); | |||||
if (que->res == NULL) { | |||||
device_printf(dev, "Unable to allocate bus resource: que interrupt [%d]\n", | |||||
vector); | |||||
return (ENXIO); | |||||
} | |||||
/* Set the handler function */ | |||||
error = bus_setup_intr(dev, que->res, | |||||
INTR_TYPE_NET | INTR_MPSAFE, NULL, | |||||
ixv_msix_que, que, &que->tag); | |||||
if (error) { | |||||
que->res = NULL; | |||||
device_printf(dev, "Failed to register QUE handler"); | |||||
return (error); | |||||
} | |||||
#if __FreeBSD_version >= 800504 | |||||
bus_describe_intr(dev, que->res, que->tag, "que %d", i); | |||||
#endif | |||||
que->msix = vector; | |||||
adapter->active_queues |= (u64)(1 << que->msix); | |||||
/* | |||||
* Bind the MSI-X 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 */ | |||||
rid = vector + 1; | |||||
adapter->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | |||||
RF_SHAREABLE | RF_ACTIVE); | |||||
if (!adapter->res) { | |||||
device_printf(dev, | |||||
"Unable to allocate bus resource: MBX interrupt [%d]\n", | |||||
rid); | |||||
return (ENXIO); | |||||
} | |||||
/* Set the mbx handler function */ | |||||
error = bus_setup_intr(dev, adapter->res, INTR_TYPE_NET | INTR_MPSAFE, | |||||
NULL, ixv_msix_mbx, adapter, &adapter->tag); | |||||
if (error) { | |||||
adapter->res = NULL; | |||||
device_printf(dev, "Failed to register LINK handler"); | |||||
return (error); | |||||
} | |||||
#if __FreeBSD_version >= 800504 | |||||
bus_describe_intr(dev, adapter->res, adapter->tag, "mbx"); | |||||
#endif | |||||
adapter->vector = vector; | |||||
/* Tasklets for Mailbox */ | |||||
TASK_INIT(&adapter->link_task, 0, ixv_handle_link, 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 | |||||
* enable the guest for MSI-X unless the vectors in | |||||
* the table are all set up, so we must rewrite the | |||||
* ENABLE in the MSI-X control register again at this | |||||
* point to cause it to successfully initialize us. | |||||
*/ | |||||
if (adapter->hw.mac.type == ixgbe_mac_82599_vf) { | |||||
pci_find_cap(dev, PCIY_MSIX, &rid); | |||||
rid += PCIR_MSIX_CTRL; | |||||
msix_ctrl = pci_read_config(dev, rid, 2); | |||||
msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; | |||||
pci_write_config(dev, rid, msix_ctrl, 2); | |||||
} | |||||
return (0); | |||||
} /* ixv_allocate_msix */ | |||||
/************************************************************************ | |||||
* ixv_configure_interrupts - Setup MSI-X resources | |||||
* | |||||
* Note: The VF device MUST use MSI-X, there is no fallback. | |||||
************************************************************************/ | |||||
static int | |||||
ixv_configure_interrupts(struct adapter *adapter) | |||||
{ | |||||
device_t dev = adapter->dev; | |||||
int rid, want, msgs; | |||||
/* Must have at least 2 MSI-X 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 MSI-X 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 MSI-X interrupts with %d vectors\n", want); | |||||
/* reflect correct sysctl value */ | |||||
ixv_num_queues = adapter->num_queues; | |||||
return (0); | |||||
} | |||||
/* 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, "MSI-X config error\n"); | |||||
return (ENXIO); | |||||
} /* ixv_configure_interrupts */ | |||||
/************************************************************************ | |||||
* ixv_handle_link - Tasklet handler for MSI-X MBX interrupts | |||||
* | |||||
* Done outside of interrupt context since the driver might sleep | |||||
************************************************************************/ | |||||
static void | |||||
ixv_handle_link(void *context, int pending) | |||||
{ | |||||
struct adapter *adapter = context; | |||||
adapter->hw.mac.ops.check_link(&adapter->hw, &adapter->link_speed, | |||||
&adapter->link_up, FALSE); | |||||
ixv_update_link_status(adapter); | |||||
} /* ixv_handle_link */ | |||||
/************************************************************************ | |||||
* ixv_check_link - Used in the local timer to poll for link changes | |||||
************************************************************************/ | |||||
static void | |||||
ixv_check_link(struct adapter *adapter) | |||||
{ | |||||
adapter->hw.mac.get_link_status = TRUE; | |||||
adapter->hw.mac.ops.check_link(&adapter->hw, &adapter->link_speed, | |||||
&adapter->link_up, FALSE); | |||||
ixv_update_link_status(adapter); | |||||
} /* ixv_check_link */ | |||||
Oh ... this should be dropped now that we configure number of queues via iflib.