Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixgbe/if_ix.c
/****************************************************************************** | /****************************************************************************** | ||||
Copyright (c) 2001-2015, Intel Corporation | Copyright (c) 2001-2016, Intel Corporation | ||||
All rights reserved. | All rights reserved. | ||||
Redistribution and use in source and binary forms, with or without | Redistribution and use in source and binary forms, with or without | ||||
modification, are permitted provided that the following conditions are met: | modification, are permitted provided that the following conditions are met: | ||||
1. Redistributions of source code must retain the above copyright notice, | 1. Redistributions of source code must retain the above copyright notice, | ||||
this list of conditions and the following disclaimer. | this list of conditions and the following disclaimer. | ||||
Show All 29 Lines | |||||
#include "ixgbe.h" | #include "ixgbe.h" | ||||
#ifdef RSS | #ifdef RSS | ||||
#include <net/rss_config.h> | #include <net/rss_config.h> | ||||
#include <netinet/in_rss.h> | #include <netinet/in_rss.h> | ||||
#endif | #endif | ||||
/********************************************************************* | /************************************************************************ | ||||
* Driver version | * Driver version | ||||
*********************************************************************/ | ************************************************************************/ | ||||
char ixgbe_driver_version[] = "3.1.13-k"; | char ixgbe_driver_version[] = "3.1.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 ixgbe_strings | * Last field stores an index into ixgbe_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 ixgbe_vendor_info_array[] = | static ixgbe_vendor_info_t ixgbe_vendor_info_array[] = | ||||
{ | { | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_DUAL_PORT, 0, 0, 0}, | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AF_SINGLE_PORT, 0, 0, 0}, | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598EB_CX4, 0, 0, 0}, | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT, 0, 0, 0}, | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598AT2, 0, 0, 0}, | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_82598, 0, 0, 0}, | ||||
Show All 22 Lines | static ixgbe_vendor_info_t ixgbe_vendor_info_array[] = | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KR, 0, 0, 0}, | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_KX4, 0, 0, 0}, | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_10G_T, 0, 0, 0}, | ||||
{IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_SFP, 0, 0, 0}, | {IXGBE_INTEL_VENDOR_ID, IXGBE_DEV_ID_X550EM_X_SFP, 0, 0, 0}, | ||||
/* required last entry */ | /* required last entry */ | ||||
{0, 0, 0, 0, 0} | {0, 0, 0, 0, 0} | ||||
}; | }; | ||||
/********************************************************************* | /************************************************************************ | ||||
* Table of branding strings | * Table of branding strings | ||||
*********************************************************************/ | ************************************************************************/ | ||||
static char *ixgbe_strings[] = { | static char *ixgbe_strings[] = { | ||||
"Intel(R) PRO/10GbE PCI-Express Network Driver" | "Intel(R) PRO/10GbE PCI-Express Network Driver" | ||||
}; | }; | ||||
/********************************************************************* | /************************************************************************ | ||||
* Function prototypes | * Function prototypes | ||||
*********************************************************************/ | ************************************************************************/ | ||||
static int ixgbe_probe(device_t); | static int ixgbe_probe(device_t); | ||||
static int ixgbe_attach(device_t); | static int ixgbe_attach(device_t); | ||||
static int ixgbe_detach(device_t); | static int ixgbe_detach(device_t); | ||||
static int ixgbe_shutdown(device_t); | static int ixgbe_shutdown(device_t); | ||||
static int ixgbe_suspend(device_t); | static int ixgbe_suspend(device_t); | ||||
static int ixgbe_resume(device_t); | static int ixgbe_resume(device_t); | ||||
static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); | static int ixgbe_ioctl(struct ifnet *, u_long, caddr_t); | ||||
static void ixgbe_init(void *); | static void ixgbe_init(void *); | ||||
static void ixgbe_init_locked(struct adapter *); | static void ixgbe_init_locked(struct adapter *); | ||||
static void ixgbe_stop(void *); | static void ixgbe_stop(void *); | ||||
#if __FreeBSD_version >= 1100036 | #if __FreeBSD_version >= 1100036 | ||||
static uint64_t ixgbe_get_counter(struct ifnet *, ift_counter); | static uint64_t ixgbe_get_counter(struct ifnet *, ift_counter); | ||||
#endif | #endif | ||||
static void ixgbe_add_media_types(struct adapter *); | static void ixgbe_add_media_types(struct adapter *); | ||||
static void ixgbe_media_status(struct ifnet *, struct ifmediareq *); | static void ixgbe_media_status(struct ifnet *, struct ifmediareq *); | ||||
static int ixgbe_media_change(struct ifnet *); | static int ixgbe_media_change(struct ifnet *); | ||||
static void ixgbe_identify_hardware(struct adapter *); | static void ixgbe_identify_hardware(struct adapter *); | ||||
static int ixgbe_allocate_pci_resources(struct adapter *); | static int ixgbe_allocate_pci_resources(struct adapter *); | ||||
static void ixgbe_get_slot_info(struct adapter *); | static void ixgbe_get_slot_info(struct adapter *); | ||||
static int ixgbe_allocate_msix(struct adapter *); | static int ixgbe_allocate_msix(struct adapter *); | ||||
static int ixgbe_allocate_legacy(struct adapter *); | static int ixgbe_allocate_legacy(struct adapter *); | ||||
static int ixgbe_setup_msix(struct adapter *); | static int ixgbe_setup_msix(struct adapter *); | ||||
static void ixgbe_free_pci_resources(struct adapter *); | static void ixgbe_free_pci_resources(struct adapter *); | ||||
static void ixgbe_local_timer(void *); | static void ixgbe_local_timer(void *); | ||||
static int ixgbe_setup_interface(device_t, struct adapter *); | static int ixgbe_setup_interface(device_t, struct adapter *); | ||||
static void ixgbe_config_gpie(struct adapter *); | static void ixgbe_config_gpie(struct adapter *); | ||||
static void ixgbe_config_dmac(struct adapter *); | static void ixgbe_config_dmac(struct adapter *); | ||||
static void ixgbe_config_delay_values(struct adapter *); | static void ixgbe_config_delay_values(struct adapter *); | ||||
static void ixgbe_config_link(struct adapter *); | static void ixgbe_config_link(struct adapter *); | ||||
static void ixgbe_check_wol_support(struct adapter *); | static void ixgbe_check_wol_support(struct adapter *); | ||||
static int ixgbe_setup_low_power_mode(struct adapter *); | static int ixgbe_setup_low_power_mode(struct adapter *); | ||||
static void ixgbe_rearm_queues(struct adapter *, u64); | static void ixgbe_rearm_queues(struct adapter *, u64); | ||||
static void ixgbe_initialize_transmit_units(struct adapter *); | static void ixgbe_initialize_transmit_units(struct adapter *); | ||||
static void ixgbe_initialize_receive_units(struct adapter *); | static void ixgbe_initialize_receive_units(struct adapter *); | ||||
static void ixgbe_enable_rx_drop(struct adapter *); | static void ixgbe_enable_rx_drop(struct adapter *); | ||||
static void ixgbe_disable_rx_drop(struct adapter *); | static void ixgbe_disable_rx_drop(struct adapter *); | ||||
static void ixgbe_initialize_rss_mapping(struct adapter *); | static void ixgbe_initialize_rss_mapping(struct adapter *); | ||||
static void ixgbe_enable_intr(struct adapter *); | static void ixgbe_enable_intr(struct adapter *); | ||||
static void ixgbe_disable_intr(struct adapter *); | static void ixgbe_disable_intr(struct adapter *); | ||||
static void ixgbe_update_stats_counters(struct adapter *); | static void ixgbe_update_stats_counters(struct adapter *); | ||||
static void ixgbe_set_promisc(struct adapter *); | static void ixgbe_set_promisc(struct adapter *); | ||||
static void ixgbe_set_multi(struct adapter *); | static void ixgbe_set_multi(struct adapter *); | ||||
static void ixgbe_update_link_status(struct adapter *); | static void ixgbe_update_link_status(struct adapter *); | ||||
static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); | static void ixgbe_set_ivar(struct adapter *, u8, u8, s8); | ||||
static void ixgbe_configure_ivars(struct adapter *); | static void ixgbe_configure_ivars(struct adapter *); | ||||
static u8 * ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); | static u8 *ixgbe_mc_array_itr(struct ixgbe_hw *, u8 **, u32 *); | ||||
static void ixgbe_setup_vlan_hw_support(struct adapter *); | static void ixgbe_setup_vlan_hw_support(struct adapter *); | ||||
static void ixgbe_register_vlan(void *, struct ifnet *, u16); | static void ixgbe_register_vlan(void *, struct ifnet *, u16); | ||||
static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); | static void ixgbe_unregister_vlan(void *, struct ifnet *, u16); | ||||
static void ixgbe_add_device_sysctls(struct adapter *); | static void ixgbe_add_device_sysctls(struct adapter *); | ||||
static void ixgbe_add_hw_stats(struct adapter *); | static void ixgbe_add_hw_stats(struct adapter *); | ||||
static int ixgbe_set_flowcntl(struct adapter *, int); | static int ixgbe_set_flowcntl(struct adapter *, int); | ||||
static int ixgbe_set_advertise(struct adapter *, int); | static int ixgbe_set_advertise(struct adapter *, int); | ||||
/* Sysctl handlers */ | /* Sysctl handlers */ | ||||
static void ixgbe_set_sysctl_value(struct adapter *, const char *, | static void ixgbe_set_sysctl_value(struct adapter *, const char *, | ||||
const char *, int *, int); | const char *, int *, int); | ||||
static int ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_flowcntl(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_advertise(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS); | ||||
#ifdef IXGBE_DEBUG | #ifdef IXGBE_DEBUG | ||||
static int ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS); | ||||
#endif | #endif | ||||
static int ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_eee_enable(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_eee_negotiated(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_eee_rx_lpi_status(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_eee_tx_lpi_status(SYSCTL_HANDLER_ARGS); | ||||
static int ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS); | static int ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS); | ||||
/* Support for pluggable optic modules */ | /* Support for pluggable optic modules */ | ||||
static bool ixgbe_sfp_probe(struct adapter *); | static bool ixgbe_sfp_probe(struct adapter *); | ||||
static void ixgbe_setup_optics(struct adapter *); | static void ixgbe_setup_optics(struct adapter *); | ||||
/* Legacy (single vector interrupt handler */ | /* Legacy (single vector) interrupt handler */ | ||||
static void ixgbe_legacy_irq(void *); | static void ixgbe_legacy_irq(void *); | ||||
/* The MSI/X Interrupt handlers */ | /* The MSI/MSI-X Interrupt handlers */ | ||||
static void ixgbe_msix_que(void *); | static void ixgbe_msix_que(void *); | ||||
static void ixgbe_msix_link(void *); | static void ixgbe_msix_link(void *); | ||||
/* Deferred interrupt tasklets */ | /* Deferred interrupt tasklets */ | ||||
static void ixgbe_handle_que(void *, int); | static void ixgbe_handle_que(void *, int); | ||||
static void ixgbe_handle_link(void *, int); | static void ixgbe_handle_link(void *, int); | ||||
static void ixgbe_handle_msf(void *, int); | static void ixgbe_handle_msf(void *, int); | ||||
static void ixgbe_handle_mod(void *, int); | static void ixgbe_handle_mod(void *, int); | ||||
static void ixgbe_handle_phy(void *, int); | static void ixgbe_handle_phy(void *, int); | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
static void ixgbe_reinit_fdir(void *, int); | static void ixgbe_reinit_fdir(void *, int); | ||||
#endif | #endif | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
static void ixgbe_ping_all_vfs(struct adapter *); | static void ixgbe_ping_all_vfs(struct adapter *); | ||||
static void ixgbe_handle_mbx(void *, int); | static void ixgbe_handle_mbx(void *, int); | ||||
static int ixgbe_init_iov(device_t, u16, const nvlist_t *); | static int ixgbe_init_iov(device_t, u16, const nvlist_t *); | ||||
static void ixgbe_uninit_iov(device_t); | static void ixgbe_uninit_iov(device_t); | ||||
static int ixgbe_add_vf(device_t, u16, const nvlist_t *); | static int ixgbe_add_vf(device_t, u16, const nvlist_t *); | ||||
static void ixgbe_initialize_iov(struct adapter *); | static void ixgbe_initialize_iov(struct adapter *); | ||||
static void ixgbe_recalculate_max_frame(struct adapter *); | static void ixgbe_recalculate_max_frame(struct adapter *); | ||||
static void ixgbe_init_vf(struct adapter *, struct ixgbe_vf *); | static void ixgbe_init_vf(struct adapter *, struct ixgbe_vf *); | ||||
#endif /* PCI_IOV */ | #endif /* PCI_IOV */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* FreeBSD Device Interface Entry Points | * FreeBSD Device Interface Entry Points | ||||
*********************************************************************/ | ************************************************************************/ | ||||
static device_method_t ix_methods[] = { | static device_method_t ix_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, ixgbe_probe), | DEVMETHOD(device_probe, ixgbe_probe), | ||||
DEVMETHOD(device_attach, ixgbe_attach), | DEVMETHOD(device_attach, ixgbe_attach), | ||||
DEVMETHOD(device_detach, ixgbe_detach), | DEVMETHOD(device_detach, ixgbe_detach), | ||||
DEVMETHOD(device_shutdown, ixgbe_shutdown), | DEVMETHOD(device_shutdown, ixgbe_shutdown), | ||||
DEVMETHOD(device_suspend, ixgbe_suspend), | DEVMETHOD(device_suspend, ixgbe_suspend), | ||||
DEVMETHOD(device_resume, ixgbe_resume), | DEVMETHOD(device_resume, ixgbe_resume), | ||||
Show All 14 Lines | |||||
MODULE_DEPEND(ix, pci, 1, 1, 1); | MODULE_DEPEND(ix, pci, 1, 1, 1); | ||||
MODULE_DEPEND(ix, ether, 1, 1, 1); | MODULE_DEPEND(ix, ether, 1, 1, 1); | ||||
#ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
MODULE_DEPEND(ix, netmap, 1, 1, 1); | MODULE_DEPEND(ix, netmap, 1, 1, 1); | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
/* | /* | ||||
** TUNEABLE PARAMETERS: | * TUNEABLE PARAMETERS: | ||||
*/ | */ | ||||
static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, | static SYSCTL_NODE(_hw, OID_AUTO, ix, CTLFLAG_RD, 0, "IXGBE driver parameters"); | ||||
"IXGBE driver parameters"); | |||||
/* | /* | ||||
** 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 ixgbe_enable_aim = TRUE; | static int ixgbe_enable_aim = TRUE; | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0, | SYSCTL_INT(_hw_ix, OID_AUTO, enable_aim, CTLFLAG_RWTUN, &ixgbe_enable_aim, 0, | ||||
"Enable adaptive interrupt moderation"); | "Enable adaptive interrupt moderation"); | ||||
static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY); | static int ixgbe_max_interrupt_rate = (4000000 / IXGBE_LOW_LATENCY); | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ix, OID_AUTO, max_interrupt_rate, CTLFLAG_RDTUN, | ||||
&ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second"); | &ixgbe_max_interrupt_rate, 0, "Maximum interrupts per second"); | ||||
/* How many packets rxeof tries to clean at a time */ | /* How many packets rxeof tries to clean at a time */ | ||||
static int ixgbe_rx_process_limit = 256; | static int ixgbe_rx_process_limit = 256; | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ix, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, | ||||
&ixgbe_rx_process_limit, 0, | &ixgbe_rx_process_limit, 0, "Maximum number of received packets to process at a time, -1 means unlimited"); | ||||
"Maximum number of received packets to process at a time," | |||||
"-1 means unlimited"); | |||||
/* How many packets txeof tries to clean at a time */ | /* How many packets txeof tries to clean at a time */ | ||||
static int ixgbe_tx_process_limit = 256; | static int ixgbe_tx_process_limit = 256; | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ix, OID_AUTO, tx_process_limit, CTLFLAG_RDTUN, | ||||
&ixgbe_tx_process_limit, 0, | &ixgbe_tx_process_limit, 0, | ||||
"Maximum number of sent packets to process at a time," | "Maximum number of sent packets to process at a time, -1 means unlimited"); | ||||
"-1 means unlimited"); | |||||
/* Flow control setting, default to full */ | /* Flow control setting, default to full */ | ||||
static int ixgbe_flow_control = ixgbe_fc_full; | static int ixgbe_flow_control = ixgbe_fc_full; | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, flow_control, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ix, OID_AUTO, flow_control, CTLFLAG_RDTUN, | ||||
&ixgbe_flow_control, 0, "Default flow control used for all adapters"); | &ixgbe_flow_control, 0, "Default flow control used for all adapters"); | ||||
/* Advertise Speed, default to 0 (auto) */ | /* Advertise Speed, default to 0 (auto) */ | ||||
static int ixgbe_advertise_speed = 0; | static int ixgbe_advertise_speed = 0; | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, advertise_speed, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_ix, OID_AUTO, advertise_speed, CTLFLAG_RDTUN, | ||||
&ixgbe_advertise_speed, 0, "Default advertised speed for all adapters"); | &ixgbe_advertise_speed, 0, "Default advertised speed for all adapters"); | ||||
/* | /* | ||||
** Smart speed setting, default to on | * Smart speed setting, default to on | ||||
** this only works as a compile option | * this only works as a compile option | ||||
** right now as its during attach, set | * right now as its during attach, set | ||||
** this to 'ixgbe_smart_speed_off' to | * this to 'ixgbe_smart_speed_off' to | ||||
** disable. | * disable. | ||||
*/ | */ | ||||
static int ixgbe_smart_speed = ixgbe_smart_speed_on; | static int ixgbe_smart_speed = ixgbe_smart_speed_on; | ||||
/* | /* | ||||
* MSIX should be the default for best performance, | * MSI-X should be the default for best performance, | ||||
* but this allows it to be forced off for testing. | * but this allows it to be forced off for testing. | ||||
*/ | */ | ||||
static int ixgbe_enable_msix = 1; | static int ixgbe_enable_msix = 1; | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0, | SYSCTL_INT(_hw_ix, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &ixgbe_enable_msix, 0, | ||||
"Enable MSI-X interrupts"); | "Enable MSI-X interrupts"); | ||||
/* | /* | ||||
* Number of Queues, can be set to 0, | * Number of Queues, can be set to 0, | ||||
* it then autoconfigures based on the | * it then autoconfigures based on the | ||||
* number of cpus with a max of 8. This | * number of cpus with a max of 8. This | ||||
* can be overriden manually here. | * can be overriden manually here. | ||||
*/ | */ | ||||
static int ixgbe_num_queues = 0; | static int ixgbe_num_queues = 0; | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0, | SYSCTL_INT(_hw_ix, OID_AUTO, num_queues, CTLFLAG_RDTUN, &ixgbe_num_queues, 0, | ||||
"Number of queues to configure, 0 indicates autoconfigure"); | "Number of queues to configure, 0 indicates autoconfigure"); | ||||
/* | /* | ||||
** Number of TX descriptors per ring, | * Number of TX descriptors per ring, | ||||
** setting higher than RX as this seems | * setting higher than RX as this seems | ||||
** the better performing choice. | * the better performing choice. | ||||
*/ | */ | ||||
static int ixgbe_txd = PERFORM_TXD; | static int ixgbe_txd = PERFORM_TXD; | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0, | SYSCTL_INT(_hw_ix, OID_AUTO, txd, CTLFLAG_RDTUN, &ixgbe_txd, 0, | ||||
"Number of transmit descriptors per queue"); | "Number of transmit descriptors per queue"); | ||||
/* Number of RX descriptors per ring */ | /* Number of RX descriptors per ring */ | ||||
static int ixgbe_rxd = PERFORM_RXD; | static int ixgbe_rxd = PERFORM_RXD; | ||||
SYSCTL_INT(_hw_ix, OID_AUTO, rxd, CTLFLAG_RDTUN, &ixgbe_rxd, 0, | SYSCTL_INT(_hw_ix, OID_AUTO, rxd, CTLFLAG_RDTUN, &ixgbe_rxd, 0, | ||||
"Number of receive descriptors per queue"); | "Number of receive descriptors per queue"); | ||||
/* | /* | ||||
** Defining this on will allow the use | * Defining this on will allow the use | ||||
** of unsupported SFP+ modules, note that | * of unsupported SFP+ modules, note that | ||||
** doing so you are on your own :) | * doing so you are on your own :) | ||||
*/ | */ | ||||
static int allow_unsupported_sfp = FALSE; | static int allow_unsupported_sfp = FALSE; | ||||
TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp); | TUNABLE_INT("hw.ix.unsupported_sfp", &allow_unsupported_sfp); | ||||
/* Keep running tab on them for sanity check */ | /* Keep running tab on them for sanity check */ | ||||
static int ixgbe_total_ports; | static int ixgbe_total_ports; | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
/* | /* | ||||
** Flow Director actually 'steals' | * Flow Director actually 'steals' | ||||
** part of the packet buffer as its | * part of the packet buffer as its | ||||
** filter pool, this variable controls | * filter pool, this variable controls | ||||
** how much it uses: | * how much it uses: | ||||
** 0 = 64K, 1 = 128K, 2 = 256K | * 0 = 64K, 1 = 128K, 2 = 256K | ||||
*/ | */ | ||||
static int fdir_pballoc = 1; | static int fdir_pballoc = 1; | ||||
#endif | #endif | ||||
#ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
/* | /* | ||||
* The #ifdef DEV_NETMAP / #endif blocks in this file are meant to | * The #ifdef DEV_NETMAP / #endif blocks in this file are meant to | ||||
* be a reference on how to implement netmap support in a driver. | * be a reference on how to implement netmap support in a driver. | ||||
* Additional comments are in ixgbe_netmap.h . | * Additional comments are in ixgbe_netmap.h . | ||||
* | * | ||||
* <dev/netmap/ixgbe_netmap.h> contains functions for netmap support | * <dev/netmap/ixgbe_netmap.h> contains functions for netmap support | ||||
* that extend the standard driver. | * that extend the standard driver. | ||||
*/ | */ | ||||
#include <dev/netmap/ixgbe_netmap.h> | #include <dev/netmap/ixgbe_netmap.h> | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
static MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations"); | static MALLOC_DEFINE(M_IXGBE, "ix", "ix driver allocations"); | ||||
/********************************************************************* | /************************************************************************ | ||||
* Device identification routine | * ixgbe_probe - Device identification routine | ||||
* | * | ||||
* ixgbe_probe determines if the driver should be loaded on | * Determines if the driver should be loaded on | ||||
* adapter based on PCI vendor/device id of the adapter. | * adapter based on its PCI vendor/device ID. | ||||
* | * | ||||
* return BUS_PROBE_DEFAULT on success, positive on failure | * return BUS_PROBE_DEFAULT on success, positive on failure | ||||
*********************************************************************/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_probe(device_t dev) | ixgbe_probe(device_t dev) | ||||
{ | { | ||||
ixgbe_vendor_info_t *ent; | ixgbe_vendor_info_t *ent; | ||||
u16 pci_vendor_id = 0; | u16 pci_vendor_id = 0; | ||||
u16 pci_device_id = 0; | u16 pci_device_id = 0; | ||||
u16 pci_subvendor_id = 0; | u16 pci_subvendor_id = 0; | ||||
u16 pci_subdevice_id = 0; | u16 pci_subdevice_id = 0; | ||||
char adapter_name[256]; | char adapter_name[256]; | ||||
INIT_DEBUGOUT("ixgbe_probe: begin"); | INIT_DEBUGOUT("ixgbe_probe: begin"); | ||||
pci_vendor_id = pci_get_vendor(dev); | pci_vendor_id = pci_get_vendor(dev); | ||||
if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) | if (pci_vendor_id != IXGBE_INTEL_VENDOR_ID) | ||||
return (ENXIO); | return (ENXIO); | ||||
pci_device_id = pci_get_device(dev); | pci_device_id = pci_get_device(dev); | ||||
pci_subvendor_id = pci_get_subvendor(dev); | pci_subvendor_id = pci_get_subvendor(dev); | ||||
pci_subdevice_id = pci_get_subdevice(dev); | pci_subdevice_id = pci_get_subdevice(dev); | ||||
ent = ixgbe_vendor_info_array; | ent = ixgbe_vendor_info_array; | ||||
while (ent->vendor_id != 0) { | while (ent->vendor_id != 0) { | ||||
if ((pci_vendor_id == ent->vendor_id) && | if ((pci_vendor_id == ent->vendor_id) && | ||||
(pci_device_id == ent->device_id) && | (pci_device_id == ent->device_id) && | ||||
((pci_subvendor_id == ent->subvendor_id) || | ((pci_subvendor_id == ent->subvendor_id) || | ||||
(ent->subvendor_id == 0)) && | (ent->subvendor_id == 0)) && | ||||
((pci_subdevice_id == ent->subdevice_id) || | ((pci_subdevice_id == ent->subdevice_id) || | ||||
(ent->subdevice_id == 0))) { | (ent->subdevice_id == 0))) { | ||||
sprintf(adapter_name, "%s, Version - %s", | sprintf(adapter_name, "%s, Version - %s", | ||||
ixgbe_strings[ent->index], | ixgbe_strings[ent->index], | ||||
ixgbe_driver_version); | ixgbe_driver_version); | ||||
device_set_desc_copy(dev, adapter_name); | device_set_desc_copy(dev, adapter_name); | ||||
++ixgbe_total_ports; | ++ixgbe_total_ports; | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
ent++; | ent++; | ||||
} | } | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } /* ixgbe_probe */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* Device initialization routine | * ixgbe_attach - Device initialization routine | ||||
* | * | ||||
* The attach entry point is called when the driver is being loaded. | * Called when the driver is being loaded. | ||||
* This routine 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 | ||||
ixgbe_attach(device_t dev) | ixgbe_attach(device_t dev) | ||||
{ | { | ||||
struct adapter *adapter; | struct adapter *adapter; | ||||
struct ixgbe_hw *hw; | struct ixgbe_hw *hw; | ||||
int error = 0; | int error = 0; | ||||
u16 csum; | u16 csum; | ||||
u32 ctrl_ext; | u32 ctrl_ext; | ||||
INIT_DEBUGOUT("ixgbe_attach: begin"); | INIT_DEBUGOUT("ixgbe_attach: begin"); | ||||
/* Allocate, clear, and link in our adapter structure */ | /* Allocate, clear, and link in our adapter structure */ | ||||
adapter = device_get_softc(dev); | adapter = device_get_softc(dev); | ||||
adapter->dev = dev; | adapter->dev = dev; | ||||
hw = &adapter->hw; | hw = &adapter->hw; | ||||
Show All 20 Lines | #endif | ||||
/* Sysctls for limiting the amount of work done in the taskqueues */ | /* Sysctls for limiting the amount of work done in the taskqueues */ | ||||
ixgbe_set_sysctl_value(adapter, "rx_processing_limit", | ixgbe_set_sysctl_value(adapter, "rx_processing_limit", | ||||
"max number of rx packets to process", | "max number of rx packets to process", | ||||
&adapter->rx_process_limit, ixgbe_rx_process_limit); | &adapter->rx_process_limit, ixgbe_rx_process_limit); | ||||
ixgbe_set_sysctl_value(adapter, "tx_processing_limit", | ixgbe_set_sysctl_value(adapter, "tx_processing_limit", | ||||
"max number of tx packets to process", | "max number of tx packets to process", | ||||
&adapter->tx_process_limit, ixgbe_tx_process_limit); | &adapter->tx_process_limit, ixgbe_tx_process_limit); | ||||
/* Do descriptor calc and sanity checks */ | /* Do descriptor calc and sanity checks */ | ||||
if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || | if (((ixgbe_txd * sizeof(union ixgbe_adv_tx_desc)) % DBA_ALIGN) != 0 || | ||||
ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { | ixgbe_txd < MIN_TXD || ixgbe_txd > MAX_TXD) { | ||||
device_printf(dev, "TXD config issue, using default!\n"); | device_printf(dev, "TXD config issue, using default!\n"); | ||||
adapter->num_tx_desc = DEFAULT_TXD; | adapter->num_tx_desc = DEFAULT_TXD; | ||||
} else | } else | ||||
adapter->num_tx_desc = ixgbe_txd; | adapter->num_tx_desc = ixgbe_txd; | ||||
/* | /* | ||||
** With many RX rings it is easy to exceed the | * With many RX rings it is easy to exceed the | ||||
** system mbuf allocation. Tuning nmbclusters | * system mbuf allocation. Tuning nmbclusters | ||||
** can alleviate this. | * can alleviate this. | ||||
*/ | */ | ||||
if (nmbclusters > 0) { | if (nmbclusters > 0) { | ||||
int s; | int s; | ||||
s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; | s = (ixgbe_rxd * adapter->num_queues) * ixgbe_total_ports; | ||||
if (s > nmbclusters) { | if (s > nmbclusters) { | ||||
device_printf(dev, "RX Descriptors exceed " | device_printf(dev, "RX Descriptors exceed system mbuf max, using default instead!\n"); | ||||
"system mbuf max, using default instead!\n"); | |||||
ixgbe_rxd = DEFAULT_RXD; | ixgbe_rxd = DEFAULT_RXD; | ||||
} | } | ||||
} | } | ||||
if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || | if (((ixgbe_rxd * sizeof(union ixgbe_adv_rx_desc)) % DBA_ALIGN) != 0 || | ||||
ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) { | ixgbe_rxd < MIN_RXD || ixgbe_rxd > MAX_RXD) { | ||||
device_printf(dev, "RXD config issue, using default!\n"); | device_printf(dev, "RXD config issue, using default!\n"); | ||||
adapter->num_rx_desc = DEFAULT_RXD; | adapter->num_rx_desc = DEFAULT_RXD; | ||||
Show All 15 Lines | if (adapter->mta == NULL) { | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
/* Initialize the shared code */ | /* Initialize the shared code */ | ||||
hw->allow_unsupported_sfp = allow_unsupported_sfp; | hw->allow_unsupported_sfp = allow_unsupported_sfp; | ||||
error = ixgbe_init_shared_code(hw); | error = ixgbe_init_shared_code(hw); | ||||
if (error == IXGBE_ERR_SFP_NOT_PRESENT) { | if (error == IXGBE_ERR_SFP_NOT_PRESENT) { | ||||
/* | /* | ||||
** No optics in this port, set up | * No optics in this port, set up | ||||
** so the timer routine will probe | * so the timer routine will probe | ||||
** for later insertion. | * for later insertion. | ||||
*/ | */ | ||||
adapter->sfp_probe = TRUE; | adapter->sfp_probe = TRUE; | ||||
error = 0; | error = 0; | ||||
} else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { | } else if (error == IXGBE_ERR_SFP_NOT_SUPPORTED) { | ||||
device_printf(dev, "Unsupported SFP+ module detected!\n"); | device_printf(dev, "Unsupported SFP+ module detected!\n"); | ||||
error = EIO; | error = EIO; | ||||
goto err_late; | goto err_late; | ||||
} else if (error) { | } else if (error) { | ||||
device_printf(dev, "Unable to initialize the shared code\n"); | device_printf(dev, "Unable to initialize the shared code\n"); | ||||
error = EIO; | error = EIO; | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
/* Make sure we have a good EEPROM before we read from it */ | /* Make sure we have a good EEPROM before we read from it */ | ||||
if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { | if (ixgbe_validate_eeprom_checksum(&adapter->hw, &csum) < 0) { | ||||
device_printf(dev, "The EEPROM Checksum Is Not Valid\n"); | device_printf(dev, "The EEPROM Checksum Is Not Valid\n"); | ||||
error = EIO; | error = EIO; | ||||
goto err_late; | goto err_late; | ||||
} | } | ||||
error = ixgbe_init_hw(hw); | error = ixgbe_init_hw(hw); | ||||
switch (error) { | switch (error) { | ||||
case IXGBE_ERR_EEPROM_VERSION: | case IXGBE_ERR_EEPROM_VERSION: | ||||
device_printf(dev, "This device is a pre-production adapter/" | device_printf(dev, "This device is a pre-production adapter/LOM. Please be aware there may be issues associated with your hardware.\nIf you are experiencing problems please contact your Intel or hardware representative who provided you with this hardware.\n"); | ||||
"LOM. Please be aware there may be issues associated " | |||||
"with your hardware.\nIf you are experiencing problems " | |||||
"please contact your Intel or hardware representative " | |||||
"who provided you with this hardware.\n"); | |||||
break; | break; | ||||
case IXGBE_ERR_SFP_NOT_SUPPORTED: | case IXGBE_ERR_SFP_NOT_SUPPORTED: | ||||
device_printf(dev, "Unsupported SFP+ Module\n"); | device_printf(dev, "Unsupported SFP+ Module\n"); | ||||
error = EIO; | error = EIO; | ||||
goto err_late; | goto err_late; | ||||
case IXGBE_ERR_SFP_NOT_PRESENT: | case IXGBE_ERR_SFP_NOT_PRESENT: | ||||
device_printf(dev, "No SFP+ Module found\n"); | device_printf(dev, "No SFP+ Module found\n"); | ||||
/* falls thru */ | /* falls thru */ | ||||
Show All 27 Lines | #endif | ||||
ixgbe_update_stats_counters(adapter); | ixgbe_update_stats_counters(adapter); | ||||
/* Register for VLAN events */ | /* Register for VLAN events */ | ||||
adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | adapter->vlan_attach = EVENTHANDLER_REGISTER(vlan_config, | ||||
ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ixgbe_register_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ||||
adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, | adapter->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig, | ||||
ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ixgbe_unregister_vlan, adapter, EVENTHANDLER_PRI_FIRST); | ||||
/* Check PCIE slot type/speed/width */ | /* Check PCIE slot type/speed/width */ | ||||
ixgbe_get_slot_info(adapter); | ixgbe_get_slot_info(adapter); | ||||
/* Set an initial default flow control & dmac value */ | /* Set an initial default flow control & dmac value */ | ||||
adapter->fc = ixgbe_fc_full; | adapter->fc = ixgbe_fc_full; | ||||
adapter->dmac = 0; | adapter->dmac = 0; | ||||
adapter->eee_enabled = 0; | adapter->eee_enabled = 0; | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
Show All 40 Lines | err_late: | ||||
ixgbe_free_transmit_structures(adapter); | ixgbe_free_transmit_structures(adapter); | ||||
ixgbe_free_receive_structures(adapter); | ixgbe_free_receive_structures(adapter); | ||||
err_out: | err_out: | ||||
if (adapter->ifp != NULL) | if (adapter->ifp != NULL) | ||||
if_free(adapter->ifp); | if_free(adapter->ifp); | ||||
ixgbe_free_pci_resources(adapter); | ixgbe_free_pci_resources(adapter); | ||||
free(adapter->mta, M_DEVBUF); | free(adapter->mta, M_DEVBUF); | ||||
return (error); | return (error); | ||||
} | } /* ixgbe_attach */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* Device removal routine | * ixgbe_detach - Device removal routine | ||||
* | * | ||||
* The detach entry point is called when the driver is being removed. | * Called when the driver is being removed. | ||||
* This routine 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 | ||||
ixgbe_detach(device_t dev) | ixgbe_detach(device_t dev) | ||||
{ | { | ||||
struct adapter *adapter = device_get_softc(dev); | struct adapter *adapter = device_get_softc(dev); | ||||
struct ix_queue *que = adapter->queues; | struct ix_queue *que = adapter->queues; | ||||
struct tx_ring *txr = adapter->tx_rings; | struct tx_ring *txr = adapter->tx_rings; | ||||
u32 ctrl_ext; | u32 ctrl_ext; | ||||
INIT_DEBUGOUT("ixgbe_detach: begin"); | INIT_DEBUGOUT("ixgbe_detach: begin"); | ||||
/* Make sure VLANS are not using driver */ | /* Make sure VLANS are not using driver */ | ||||
if (adapter->ifp->if_vlantrunk != NULL) { | if (adapter->ifp->if_vlantrunk != NULL) { | ||||
device_printf(dev,"Vlan in use, detach first\n"); | device_printf(dev,"Vlan in use, detach first\n"); | ||||
return (EBUSY); | return (EBUSY); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | #endif /* DEV_NETMAP */ | ||||
bus_generic_detach(dev); | bus_generic_detach(dev); | ||||
if_free(adapter->ifp); | if_free(adapter->ifp); | ||||
ixgbe_free_transmit_structures(adapter); | ixgbe_free_transmit_structures(adapter); | ||||
ixgbe_free_receive_structures(adapter); | ixgbe_free_receive_structures(adapter); | ||||
free(adapter->mta, M_DEVBUF); | free(adapter->mta, M_DEVBUF); | ||||
IXGBE_CORE_LOCK_DESTROY(adapter); | IXGBE_CORE_LOCK_DESTROY(adapter); | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_detach */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * ixgbe_shutdown - Shutdown entry point | ||||
* Shutdown entry point | ************************************************************************/ | ||||
* | |||||
**********************************************************************/ | |||||
static int | static int | ||||
ixgbe_shutdown(device_t dev) | ixgbe_shutdown(device_t dev) | ||||
{ | { | ||||
struct adapter *adapter = device_get_softc(dev); | struct adapter *adapter = device_get_softc(dev); | ||||
int error = 0; | int error = 0; | ||||
INIT_DEBUGOUT("ixgbe_shutdown: begin"); | INIT_DEBUGOUT("ixgbe_shutdown: begin"); | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
error = ixgbe_setup_low_power_mode(adapter); | error = ixgbe_setup_low_power_mode(adapter); | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
return (error); | return (error); | ||||
} | } /* ixgbe_shutdown */ | ||||
/** | /************************************************************************ | ||||
* Methods for going from: | * ixgbe_suspend | ||||
* D0 -> D3: ixgbe_suspend | * | ||||
* D3 -> D0: ixgbe_resume | * From D0 to D3 | ||||
*/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_suspend(device_t dev) | ixgbe_suspend(device_t dev) | ||||
{ | { | ||||
struct adapter *adapter = device_get_softc(dev); | struct adapter *adapter = device_get_softc(dev); | ||||
int error = 0; | int error = 0; | ||||
INIT_DEBUGOUT("ixgbe_suspend: begin"); | INIT_DEBUGOUT("ixgbe_suspend: begin"); | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
error = ixgbe_setup_low_power_mode(adapter); | error = ixgbe_setup_low_power_mode(adapter); | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
return (error); | return (error); | ||||
} | } /* ixgbe_suspend */ | ||||
/************************************************************************ | |||||
* ixgbe_resume | |||||
* | |||||
* From D3 to D0 | |||||
************************************************************************/ | |||||
static int | static int | ||||
ixgbe_resume(device_t dev) | ixgbe_resume(device_t dev) | ||||
{ | { | ||||
struct adapter *adapter = device_get_softc(dev); | struct adapter *adapter = device_get_softc(dev); | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 wus; | u32 wus; | ||||
INIT_DEBUGOUT("ixgbe_resume: begin"); | INIT_DEBUGOUT("ixgbe_resume: begin"); | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
/* Read & clear WUS register */ | /* Read & clear WUS register */ | ||||
wus = IXGBE_READ_REG(hw, IXGBE_WUS); | wus = IXGBE_READ_REG(hw, IXGBE_WUS); | ||||
if (wus) | if (wus) | ||||
device_printf(dev, "Woken up by (WUS): %#010x\n", | device_printf(dev, "Woken up by (WUS): %#010x\n", | ||||
IXGBE_READ_REG(hw, IXGBE_WUS)); | IXGBE_READ_REG(hw, IXGBE_WUS)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); | IXGBE_WRITE_REG(hw, IXGBE_WUS, 0xffffffff); | ||||
/* And clear WUFC until next low-power transition */ | /* And clear WUFC until next low-power transition */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); | IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0); | ||||
/* | /* | ||||
* Required after D3->D0 transition; | * Required after D3->D0 transition; | ||||
* will re-advertise all previous advertised speeds | * will re-advertise all previous advertised speeds | ||||
*/ | */ | ||||
if (ifp->if_flags & IFF_UP) | if (ifp->if_flags & IFF_UP) | ||||
ixgbe_init_locked(adapter); | ixgbe_init_locked(adapter); | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_resume */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* Ioctl entry point | * ixgbe_ioctl - Ioctl entry point | ||||
* | * | ||||
* ixgbe_ioctl is called when the user wants to configure the | * Called when the user wants to configure the interface. | ||||
* interface. | |||||
* | * | ||||
* return 0 on success, positive on failure | * return 0 on success, positive on failure | ||||
**********************************************************************/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_ioctl(struct ifnet * ifp, u_long command, caddr_t data) | ixgbe_ioctl(struct ifnet *ifp, u_long command, caddr_t data) | ||||
{ | { | ||||
struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = ifp->if_softc; | ||||
struct ifreq *ifr = (struct ifreq *) data; | struct ifreq *ifr = (struct ifreq *) data; | ||||
#if defined(INET) || defined(INET6) | #if defined(INET) || defined(INET6) | ||||
struct ifaddr *ifa = (struct ifaddr *)data; | struct ifaddr *ifa = (struct ifaddr *)data; | ||||
#endif | #endif | ||||
int error = 0; | int error = 0; | ||||
bool avoid_reset = FALSE; | bool avoid_reset = FALSE; | ||||
switch (command) { | switch (command) { | ||||
case SIOCSIFADDR: | case SIOCSIFADDR: | ||||
#ifdef INET | #ifdef INET | ||||
if (ifa->ifa_addr->sa_family == AF_INET) | if (ifa->ifa_addr->sa_family == AF_INET) | ||||
avoid_reset = TRUE; | avoid_reset = TRUE; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (ifa->ifa_addr->sa_family == AF_INET6) | if (ifa->ifa_addr->sa_family == AF_INET6) | ||||
avoid_reset = TRUE; | avoid_reset = TRUE; | ||||
#endif | #endif | ||||
/* | /* | ||||
** Calling init results in link renegotiation, | * Calling init results in link renegotiation, | ||||
** so we avoid doing it when possible. | * so we avoid doing it when possible. | ||||
*/ | */ | ||||
if (avoid_reset) { | if (avoid_reset) { | ||||
ifp->if_flags |= IFF_UP; | ifp->if_flags |= IFF_UP; | ||||
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) | if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) | ||||
ixgbe_init(adapter); | ixgbe_init(adapter); | ||||
#ifdef INET | #ifdef INET | ||||
if (!(ifp->if_flags & IFF_NOARP)) | if (!(ifp->if_flags & IFF_NOARP)) | ||||
arp_ifinit(ifp, ifa); | arp_ifinit(ifp, ifa); | ||||
#endif | #endif | ||||
} else | } else | ||||
error = ether_ioctl(ifp, command, data); | error = ether_ioctl(ifp, command, data); | ||||
break; | break; | ||||
case SIOCSIFMTU: | case SIOCSIFMTU: | ||||
IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); | IOCTL_DEBUGOUT("ioctl: SIOCSIFMTU (Set Interface MTU)"); | ||||
if (ifr->ifr_mtu > IXGBE_MAX_MTU) { | if (ifr->ifr_mtu > IXGBE_MAX_MTU) { | ||||
error = EINVAL; | error = EINVAL; | ||||
} else { | } else { | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
ifp->if_mtu = ifr->ifr_mtu; | ifp->if_mtu = ifr->ifr_mtu; | ||||
adapter->max_frame_size = | adapter->max_frame_size = ifp->if_mtu + IXGBE_MTU_HDR; | ||||
ifp->if_mtu + IXGBE_MTU_HDR; | |||||
ixgbe_init_locked(adapter); | ixgbe_init_locked(adapter); | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
ixgbe_recalculate_max_frame(adapter); | ixgbe_recalculate_max_frame(adapter); | ||||
#endif | #endif | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
} | } | ||||
break; | break; | ||||
case SIOCSIFFLAGS: | case SIOCSIFFLAGS: | ||||
IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); | IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
if (ifp->if_flags & IFF_UP) { | if (ifp->if_flags & IFF_UP) { | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { | if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { | ||||
if ((ifp->if_flags ^ adapter->if_flags) & | if ((ifp->if_flags ^ adapter->if_flags) & | ||||
(IFF_PROMISC | IFF_ALLMULTI)) { | (IFF_PROMISC | IFF_ALLMULTI)) { | ||||
ixgbe_set_promisc(adapter); | ixgbe_set_promisc(adapter); | ||||
} | } | ||||
} else | } else | ||||
ixgbe_init_locked(adapter); | ixgbe_init_locked(adapter); | ||||
} else | } else | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (ifp->if_drv_flags & IFF_DRV_RUNNING) | ||||
ixgbe_stop(adapter); | ixgbe_stop(adapter); | ||||
adapter->if_flags = ifp->if_flags; | adapter->if_flags = ifp->if_flags; | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
default: | default: | ||||
IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); | IOCTL_DEBUGOUT1("ioctl: UNKNOWN (0x%X)\n", (int)command); | ||||
error = ether_ioctl(ifp, command, data); | error = ether_ioctl(ifp, command, data); | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } /* ixgbe_ioctl */ | ||||
/* | /* | ||||
* Set the various hardware offload abilities. | * Set the various hardware offload abilities. | ||||
* | * | ||||
* This takes the ifnet's if_capenable flags (e.g. set by the user using | * This takes the ifnet's if_capenable flags (e.g. set by the user using | ||||
* ifconfig) and indicates to the OS via the ifnet's if_hwassist field what | * ifconfig) and indicates to the OS via the ifnet's if_hwassist field what | ||||
* mbuf offload flags the driver will understand. | * mbuf offload flags the driver will understand. | ||||
*/ | */ | ||||
Show All 25 Lines | #else | ||||
if (ifp->if_capenable & IFCAP_TXCSUM) { | if (ifp->if_capenable & IFCAP_TXCSUM) { | ||||
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | ||||
if (hw->mac.type != ixgbe_mac_82598EB) | if (hw->mac.type != ixgbe_mac_82598EB) | ||||
ifp->if_hwassist |= CSUM_SCTP; | ifp->if_hwassist |= CSUM_SCTP; | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
/********************************************************************* | /************************************************************************ | ||||
* Init entry point | * ixgbe_init_locked - Init entry point | ||||
* | * | ||||
* This routine is used in two ways. It is used by the stack as | * Used in two ways: It is used by the stack as an init | ||||
* init entry point in network interface structure. It is also used | * entry point in network interface structure. It is also | ||||
* by the driver as a hw/sw initialization routine to get to a | * used by the driver as a hw/sw initialization routine to | ||||
* consistent state. | * get to a consistent state. | ||||
* | * | ||||
* return 0 on success, positive on failure | * return 0 on success, positive on failure | ||||
**********************************************************************/ | ************************************************************************/ | ||||
#define IXGBE_MHADD_MFS_SHIFT 16 | #define IXGBE_MHADD_MFS_SHIFT 16 | ||||
static void | static void | ||||
ixgbe_init_locked(struct adapter *adapter) | ixgbe_init_locked(struct adapter *adapter) | ||||
{ | { | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
struct tx_ring *txr; | struct tx_ring *txr; | ||||
struct rx_ring *rxr; | struct rx_ring *rxr; | ||||
u32 txdctl, mhadd; | u32 txdctl, mhadd; | ||||
u32 rxdctl, rxctrl; | u32 rxdctl, rxctrl; | ||||
int err = 0; | int err = 0; | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
enum ixgbe_iov_mode mode; | enum ixgbe_iov_mode mode; | ||||
#endif | #endif | ||||
mtx_assert(&adapter->core_mtx, MA_OWNED); | mtx_assert(&adapter->core_mtx, MA_OWNED); | ||||
INIT_DEBUGOUT("ixgbe_init_locked: begin"); | INIT_DEBUGOUT("ixgbe_init_locked: begin"); | ||||
hw->adapter_stopped = FALSE; | hw->adapter_stopped = FALSE; | ||||
ixgbe_stop_adapter(hw); | ixgbe_stop_adapter(hw); | ||||
callout_stop(&adapter->timer); | callout_stop(&adapter->timer); | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
mode = ixgbe_get_iov_mode(adapter); | mode = ixgbe_get_iov_mode(adapter); | ||||
adapter->pool = ixgbe_max_vfs(mode); | adapter->pool = ixgbe_max_vfs(mode); | ||||
/* Queue indices may change with IOV mode */ | /* Queue indices may change with IOV mode */ | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0; i < adapter->num_queues; i++) { | ||||
adapter->rx_rings[i].me = ixgbe_pf_que_index(mode, i); | adapter->rx_rings[i].me = ixgbe_pf_que_index(mode, i); | ||||
adapter->tx_rings[i].me = ixgbe_pf_que_index(mode, i); | adapter->tx_rings[i].me = ixgbe_pf_que_index(mode, i); | ||||
} | } | ||||
#endif | #endif | ||||
/* reprogram the RAR[0] in case user changed it. */ | /* reprogram the RAR[0] in case user changed it. */ | ||||
ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, IXGBE_RAH_AV); | ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 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(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); | bcopy(IF_LLADDR(ifp), hw->mac.addr, IXGBE_ETH_LENGTH_OF_ADDRESS); | ||||
ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 1); | ixgbe_set_rar(hw, 0, hw->mac.addr, adapter->pool, 1); | ||||
hw->addr_ctrl.rar_used_count = 1; | hw->addr_ctrl.rar_used_count = 1; | ||||
/* Set hardware offload abilities from ifnet flags */ | /* Set hardware offload abilities from ifnet flags */ | ||||
Show All 26 Lines | if (ixgbe_setup_receive_structures(adapter)) { | ||||
device_printf(dev, "Could not setup receive structures\n"); | device_printf(dev, "Could not setup receive structures\n"); | ||||
ixgbe_stop(adapter); | ixgbe_stop(adapter); | ||||
return; | return; | ||||
} | } | ||||
/* Configure RX settings */ | /* Configure RX settings */ | ||||
ixgbe_initialize_receive_units(adapter); | ixgbe_initialize_receive_units(adapter); | ||||
/* Enable SDP & MSIX interrupts based on adapter */ | /* Enable SDP & MSI-X interrupts based on adapter */ | ||||
ixgbe_config_gpie(adapter); | ixgbe_config_gpie(adapter); | ||||
/* Set MTU size */ | /* Set MTU size */ | ||||
if (ifp->if_mtu > ETHERMTU) { | if (ifp->if_mtu > ETHERMTU) { | ||||
/* aka IXGBE_MAXFRS on 82599 and newer */ | /* aka IXGBE_MAXFRS on 82599 and newer */ | ||||
mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); | mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); | ||||
mhadd &= ~IXGBE_MHADD_MFS_MASK; | mhadd &= ~IXGBE_MHADD_MFS_MASK; | ||||
mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; | mhadd |= adapter->max_frame_size << IXGBE_MHADD_MFS_SHIFT; | ||||
IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); | IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd); | ||||
} | } | ||||
/* Now enable all the queues */ | /* Now enable all the queues */ | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0; i < adapter->num_queues; i++) { | ||||
txr = &adapter->tx_rings[i]; | txr = &adapter->tx_rings[i]; | ||||
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me)); | txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txr->me)); | ||||
txdctl |= IXGBE_TXDCTL_ENABLE; | txdctl |= IXGBE_TXDCTL_ENABLE; | ||||
/* Set WTHRESH to 8, burst writeback */ | /* Set WTHRESH to 8, burst writeback */ | ||||
txdctl |= (8 << 16); | txdctl |= (8 << 16); | ||||
/* | /* | ||||
* When the internal queue falls below PTHRESH (32), | * When the internal queue falls below PTHRESH (32), | ||||
* start prefetching as long as there are at least | * start prefetching as long as there are at least | ||||
* HTHRESH (1) buffers ready. The values are taken | * HTHRESH (1) buffers ready. The values are taken | ||||
* from the Intel linux driver 3.8.21. | * from the Intel linux driver 3.8.21. | ||||
* Prefetching enables tx line rate even with 1 queue. | * Prefetching enables tx line rate even with 1 queue. | ||||
*/ | */ | ||||
txdctl |= (32 << 0) | (1 << 8); | txdctl |= (32 << 0) | (1 << 8); | ||||
IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl); | IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txr->me), txdctl); | ||||
} | } | ||||
for (int i = 0, j = 0; i < adapter->num_queues; i++) { | for (int i = 0, j = 0; i < adapter->num_queues; i++) { | ||||
rxr = &adapter->rx_rings[i]; | rxr = &adapter->rx_rings[i]; | ||||
rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); | rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); | ||||
if (hw->mac.type == ixgbe_mac_82598EB) { | if (hw->mac.type == ixgbe_mac_82598EB) { | ||||
/* | /* | ||||
** PTHRESH = 21 | * PTHRESH = 21 | ||||
** HTHRESH = 4 | * HTHRESH = 4 | ||||
** WTHRESH = 8 | * WTHRESH = 8 | ||||
*/ | */ | ||||
rxdctl &= ~0x3FFFFF; | rxdctl &= ~0x3FFFFF; | ||||
rxdctl |= 0x080420; | rxdctl |= 0x080420; | ||||
} | } | ||||
rxdctl |= IXGBE_RXDCTL_ENABLE; | rxdctl |= IXGBE_RXDCTL_ENABLE; | ||||
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl); | IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), rxdctl); | ||||
for (; j < 10; j++) { | for (; j < 10; j++) { | ||||
if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) & | if (IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)) & | ||||
IXGBE_RXDCTL_ENABLE) | IXGBE_RXDCTL_ENABLE) | ||||
Show All 34 Lines | #endif /* DEV_NETMAP */ | ||||
rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); | rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); | ||||
if (hw->mac.type == ixgbe_mac_82598EB) | if (hw->mac.type == ixgbe_mac_82598EB) | ||||
rxctrl |= IXGBE_RXCTRL_DMBYPS; | rxctrl |= IXGBE_RXCTRL_DMBYPS; | ||||
rxctrl |= IXGBE_RXCTRL_RXEN; | rxctrl |= IXGBE_RXCTRL_RXEN; | ||||
ixgbe_enable_rx_dma(hw, rxctrl); | ixgbe_enable_rx_dma(hw, rxctrl); | ||||
callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); | callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); | ||||
/* Set up MSI/X routing */ | /* Set up MSI-X routing */ | ||||
if (ixgbe_enable_msix) { | if (ixgbe_enable_msix) { | ||||
ixgbe_configure_ivars(adapter); | ixgbe_configure_ivars(adapter); | ||||
/* Set up auto-mask */ | /* Set up auto-mask */ | ||||
if (hw->mac.type == ixgbe_mac_82598EB) | if (hw->mac.type == ixgbe_mac_82598EB) | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); | IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); | ||||
else { | else { | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); | IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); | IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); | ||||
} | } | ||||
} else { /* Simple settings for Legacy/MSI */ | } else { /* Simple settings for Legacy/MSI */ | ||||
ixgbe_set_ivar(adapter, 0, 0, 0); | ixgbe_set_ivar(adapter, 0, 0, 0); | ||||
ixgbe_set_ivar(adapter, 0, 0, 1); | ixgbe_set_ivar(adapter, 0, 0, 1); | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); | IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); | ||||
} | } | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
/* Init Flow director */ | /* Init Flow director */ | ||||
if (hw->mac.type != ixgbe_mac_82598EB) { | if (hw->mac.type != ixgbe_mac_82598EB) { | ||||
u32 hdrm = 32 << fdir_pballoc; | u32 hdrm = 32 << fdir_pballoc; | ||||
hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); | hw->mac.ops.setup_rxpba(hw, 0, hdrm, PBA_STRATEGY_EQUAL); | ||||
ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); | ixgbe_init_fdir_signature_82599(&adapter->hw, fdir_pballoc); | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Check on any SFP devices that | * Check on any SFP devices that | ||||
* need to be kick-started | * need to be kick-started | ||||
*/ | */ | ||||
if (hw->phy.type == ixgbe_phy_none) { | if (hw->phy.type == ixgbe_phy_none) { | ||||
err = hw->phy.ops.identify(hw); | err = hw->phy.ops.identify(hw); | ||||
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { | if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Unsupported SFP+ module type was detected.\n"); | "Unsupported SFP+ module type was detected.\n"); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
/* Set moderation on the Link interrupt */ | /* Set moderation on the Link interrupt */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); | IXGBE_WRITE_REG(hw, IXGBE_EITR(adapter->vector), IXGBE_LINK_ITR); | ||||
/* Configure Energy Efficient Ethernet for supported devices */ | /* Configure Energy Efficient Ethernet for supported devices */ | ||||
if (hw->mac.ops.setup_eee) { | if (hw->mac.ops.setup_eee) { | ||||
err = hw->mac.ops.setup_eee(hw, adapter->eee_enabled); | err = hw->mac.ops.setup_eee(hw, adapter->eee_enabled); | ||||
Show All 30 Lines | /* Enable the use of the MBX by the VF's */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, reg); | IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, reg); | ||||
} | } | ||||
#endif | #endif | ||||
/* 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; | ||||
return; | return; | ||||
} | } /* ixgbe_init_locked */ | ||||
/************************************************************************ | |||||
* ixgbe_init | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_init(void *arg) | ixgbe_init(void *arg) | ||||
{ | { | ||||
struct adapter *adapter = arg; | struct adapter *adapter = arg; | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
ixgbe_init_locked(adapter); | ixgbe_init_locked(adapter); | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
return; | return; | ||||
} | } /* ixgbe_init */ | ||||
/************************************************************************ | |||||
* ixgbe_config_gpie | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_config_gpie(struct adapter *adapter) | ixgbe_config_gpie(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 gpie; | u32 gpie; | ||||
gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); | gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); | ||||
/* Fan Failure Interrupt */ | /* Fan Failure Interrupt */ | ||||
if (hw->device_id == IXGBE_DEV_ID_82598AT) | if (hw->device_id == IXGBE_DEV_ID_82598AT) | ||||
gpie |= IXGBE_SDP1_GPIEN; | gpie |= IXGBE_SDP1_GPIEN; | ||||
/* | /* | ||||
Show All 11 Lines | ixgbe_config_gpie(struct adapter *adapter) | ||||
* Link Detection (X552 SFP+, X552/X557-AT) | * Link Detection (X552 SFP+, X552/X557-AT) | ||||
*/ | */ | ||||
if (hw->mac.type == ixgbe_mac_X540 || | if (hw->mac.type == ixgbe_mac_X540 || | ||||
hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || | hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP || | ||||
hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) | hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) | ||||
gpie |= IXGBE_SDP0_GPIEN_X540; | gpie |= IXGBE_SDP0_GPIEN_X540; | ||||
if (adapter->msix > 1) { | if (adapter->msix > 1) { | ||||
/* Enable Enhanced MSIX mode */ | /* Enable Enhanced MSI-X mode */ | ||||
gpie |= IXGBE_GPIE_MSIX_MODE; | gpie |= IXGBE_GPIE_MSIX_MODE; | ||||
gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | | gpie |= IXGBE_GPIE_EIAME | IXGBE_GPIE_PBA_SUPPORT | | ||||
IXGBE_GPIE_OCD; | IXGBE_GPIE_OCD; | ||||
} | } | ||||
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); | IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); | ||||
return; | return; | ||||
} | } /* ixgbe_config_gpie */ | ||||
/* | /************************************************************************ | ||||
* ixgbe_config_delay_values | |||||
* | |||||
* Requires adapter->max_frame_size to be set. | * Requires adapter->max_frame_size to be set. | ||||
*/ | ************************************************************************/ | ||||
static void | static void | ||||
ixgbe_config_delay_values(struct adapter *adapter) | ixgbe_config_delay_values(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 rxpb, frame, size, tmp; | u32 rxpb, frame, size, tmp; | ||||
frame = adapter->max_frame_size; | frame = adapter->max_frame_size; | ||||
/* Calculate High Water */ | /* Calculate High Water */ | ||||
switch (hw->mac.type) { | switch (hw->mac.type) { | ||||
case ixgbe_mac_X540: | case ixgbe_mac_X540: | ||||
case ixgbe_mac_X550: | case ixgbe_mac_X550: | ||||
case ixgbe_mac_X550EM_x: | case ixgbe_mac_X550EM_x: | ||||
Show All 18 Lines | default: | ||||
tmp = IXGBE_LOW_DV(frame); | tmp = IXGBE_LOW_DV(frame); | ||||
break; | break; | ||||
} | } | ||||
hw->fc.low_water[0] = IXGBE_BT2KB(tmp); | hw->fc.low_water[0] = IXGBE_BT2KB(tmp); | ||||
hw->fc.requested_mode = adapter->fc; | hw->fc.requested_mode = adapter->fc; | ||||
hw->fc.pause_time = IXGBE_FC_PAUSE; | hw->fc.pause_time = IXGBE_FC_PAUSE; | ||||
hw->fc.send_xon = TRUE; | hw->fc.send_xon = TRUE; | ||||
} | } /* ixgbe_config_delay_values */ | ||||
/* | /* | ||||
** | ** | ||||
** MSIX Interrupt Handlers and Tasklets | ** MSI-X Interrupt Handlers and Tasklets | ||||
** | ** | ||||
*/ | */ | ||||
static inline void | static inline void | ||||
ixgbe_enable_queue(struct adapter *adapter, u32 vector) | ixgbe_enable_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); | ||||
Show All 27 Lines | if (hw->mac.type == ixgbe_mac_82598EB) { | ||||
if (mask) | if (mask) | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); | IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask); | ||||
mask = (queue >> 32); | mask = (queue >> 32); | ||||
if (mask) | if (mask) | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); | IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(1), mask); | ||||
} | } | ||||
} | } | ||||
/************************************************************************ | |||||
* ixgbe_handle_que | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_handle_que(void *context, int pending) | ixgbe_handle_que(void *context, int pending) | ||||
{ | { | ||||
struct ix_queue *que = context; | struct ix_queue *que = context; | ||||
struct adapter *adapter = que->adapter; | struct adapter *adapter = que->adapter; | ||||
struct tx_ring *txr = que->txr; | struct tx_ring *txr = que->txr; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
Show All 11 Lines | #endif | ||||
IXGBE_TX_UNLOCK(txr); | IXGBE_TX_UNLOCK(txr); | ||||
} | } | ||||
/* Reenable this interrupt */ | /* Reenable this interrupt */ | ||||
if (que->res != NULL) | if (que->res != NULL) | ||||
ixgbe_enable_queue(adapter, que->msix); | ixgbe_enable_queue(adapter, que->msix); | ||||
else | else | ||||
ixgbe_enable_intr(adapter); | ixgbe_enable_intr(adapter); | ||||
return; | return; | ||||
} | } /* ixgbe_handle_que */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * ixgbe_legacy_irq - Legacy Interrupt Service routine | ||||
* Legacy Interrupt Service routine | ************************************************************************/ | ||||
* | |||||
**********************************************************************/ | |||||
static void | static void | ||||
ixgbe_legacy_irq(void *arg) | ixgbe_legacy_irq(void *arg) | ||||
{ | { | ||||
struct ix_queue *que = arg; | struct ix_queue *que = arg; | ||||
struct adapter *adapter = que->adapter; | struct adapter *adapter = que->adapter; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
struct tx_ring *txr = adapter->tx_rings; | struct tx_ring *txr = adapter->tx_rings; | ||||
bool more; | bool more; | ||||
u32 reg_eicr; | u32 eicr; | ||||
reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICR); | eicr = IXGBE_READ_REG(hw, IXGBE_EICR); | ||||
++que->irqs; | ++que->irqs; | ||||
if (reg_eicr == 0) { | if (eicr == 0) { | ||||
ixgbe_enable_intr(adapter); | ixgbe_enable_intr(adapter); | ||||
return; | return; | ||||
} | } | ||||
more = ixgbe_rxeof(que); | more = ixgbe_rxeof(que); | ||||
IXGBE_TX_LOCK(txr); | IXGBE_TX_LOCK(txr); | ||||
ixgbe_txeof(txr); | ixgbe_txeof(txr); | ||||
#ifdef IXGBE_LEGACY_TX | #ifdef IXGBE_LEGACY_TX | ||||
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) | if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) | ||||
ixgbe_start_locked(txr, ifp); | ixgbe_start_locked(txr, ifp); | ||||
#else | #else | ||||
if (!drbr_empty(ifp, txr->br)) | if (!drbr_empty(ifp, txr->br)) | ||||
ixgbe_mq_start_locked(ifp, txr); | ixgbe_mq_start_locked(ifp, txr); | ||||
#endif | #endif | ||||
IXGBE_TX_UNLOCK(txr); | IXGBE_TX_UNLOCK(txr); | ||||
/* Check for fan failure */ | /* Check for fan failure */ | ||||
if ((hw->device_id == IXGBE_DEV_ID_82598AT) && | if ((hw->device_id == IXGBE_DEV_ID_82598AT) && | ||||
(reg_eicr & IXGBE_EICR_GPI_SDP1)) { | (eicr & IXGBE_EICR_GPI_SDP1)) { | ||||
device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " | device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " | ||||
"REPLACE IMMEDIATELY!!\n"); | "REPLACE IMMEDIATELY!!\n"); | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); | IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); | ||||
} | } | ||||
/* Link status change */ | /* Link status change */ | ||||
if (reg_eicr & IXGBE_EICR_LSC) | if (eicr & IXGBE_EICR_LSC) | ||||
taskqueue_enqueue(adapter->tq, &adapter->link_task); | taskqueue_enqueue(adapter->tq, &adapter->link_task); | ||||
/* External PHY interrupt */ | /* External PHY interrupt */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && | ||||
(reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) | (eicr & IXGBE_EICR_GPI_SDP0_X540)) | ||||
taskqueue_enqueue(adapter->tq, &adapter->phy_task); | taskqueue_enqueue(adapter->tq, &adapter->phy_task); | ||||
if (more) | if (more) | ||||
taskqueue_enqueue(que->tq, &que->que_task); | taskqueue_enqueue(que->tq, &que->que_task); | ||||
else | else | ||||
ixgbe_enable_intr(adapter); | ixgbe_enable_intr(adapter); | ||||
return; | return; | ||||
} | } /* ixgbe_legacy_irq */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * ixgbe_msix_que - MSI-X Queue Interrupt Service routine | ||||
* MSIX Queue Interrupt Service routine | ************************************************************************/ | ||||
* | |||||
**********************************************************************/ | |||||
void | void | ||||
ixgbe_msix_que(void *arg) | ixgbe_msix_que(void *arg) | ||||
{ | { | ||||
struct ix_queue *que = arg; | struct ix_queue *que = arg; | ||||
struct adapter *adapter = que->adapter; | struct adapter *adapter = que->adapter; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
struct tx_ring *txr = que->txr; | struct tx_ring *txr = que->txr; | ||||
struct rx_ring *rxr = que->rxr; | struct rx_ring *rxr = que->rxr; | ||||
bool more; | bool more; | ||||
u32 newitr = 0; | u32 newitr = 0; | ||||
/* Protect against spurious interrupts */ | /* Protect against spurious interrupts */ | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | ||||
return; | return; | ||||
ixgbe_disable_queue(adapter, que->msix); | ixgbe_disable_queue(adapter, que->msix); | ||||
++que->irqs; | ++que->irqs; | ||||
Show All 11 Lines | |||||
#endif | #endif | ||||
IXGBE_TX_UNLOCK(txr); | IXGBE_TX_UNLOCK(txr); | ||||
/* Do AIM now? */ | /* Do AIM now? */ | ||||
if (adapter->enable_aim == FALSE) | if (adapter->enable_aim == FALSE) | ||||
goto no_calc; | goto no_calc; | ||||
/* | /* | ||||
** Do Adaptive Interrupt Moderation: | * Do Adaptive Interrupt Moderation: | ||||
** - Write out last calculated setting | * - Write out last calculated setting | ||||
** - Calculate based on average size over | * - Calculate based on average size over | ||||
** the last interval. | * the last interval. | ||||
*/ | */ | ||||
if (que->eitr_setting) | if (que->eitr_setting) | ||||
IXGBE_WRITE_REG(&adapter->hw, | IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(que->msix), | ||||
IXGBE_EITR(que->msix), que->eitr_setting); | que->eitr_setting); | ||||
que->eitr_setting = 0; | que->eitr_setting = 0; | ||||
/* Idle, do nothing */ | /* Idle, do nothing */ | ||||
if ((txr->bytes == 0) && (rxr->bytes == 0)) | if ((txr->bytes == 0) && (rxr->bytes == 0)) | ||||
goto no_calc; | goto no_calc; | ||||
if ((txr->bytes) && (txr->packets)) | if ((txr->bytes) && (txr->packets)) | ||||
newitr = txr->bytes/txr->packets; | newitr = txr->bytes/txr->packets; | ||||
if ((rxr->bytes) && (rxr->packets)) | if ((rxr->bytes) && (rxr->packets)) | ||||
newitr = max(newitr, | newitr = max(newitr, (rxr->bytes / rxr->packets)); | ||||
(rxr->bytes / rxr->packets)); | |||||
newitr += 24; /* account for hardware frame, crc */ | newitr += 24; /* account for hardware frame, crc */ | ||||
/* set an upper boundary */ | /* set an upper boundary */ | ||||
newitr = min(newitr, 3000); | newitr = min(newitr, 3000); | ||||
/* Be nice to the mid range */ | /* Be nice to the mid range */ | ||||
if ((newitr > 300) && (newitr < 1200)) | if ((newitr > 300) && (newitr < 1200)) | ||||
newitr = (newitr / 3); | newitr = (newitr / 3); | ||||
else | else | ||||
newitr = (newitr / 2); | newitr = (newitr / 2); | ||||
if (adapter->hw.mac.type == ixgbe_mac_82598EB) | if (adapter->hw.mac.type == ixgbe_mac_82598EB) | ||||
newitr |= newitr << 16; | newitr |= newitr << 16; | ||||
else | else | ||||
newitr |= IXGBE_EITR_CNT_WDIS; | newitr |= IXGBE_EITR_CNT_WDIS; | ||||
/* save for next interrupt */ | /* save for next interrupt */ | ||||
que->eitr_setting = newitr; | que->eitr_setting = newitr; | ||||
/* Reset state */ | /* Reset state */ | ||||
txr->bytes = 0; | txr->bytes = 0; | ||||
txr->packets = 0; | txr->packets = 0; | ||||
rxr->bytes = 0; | rxr->bytes = 0; | ||||
rxr->packets = 0; | rxr->packets = 0; | ||||
no_calc: | no_calc: | ||||
if (more) | if (more) | ||||
taskqueue_enqueue(que->tq, &que->que_task); | taskqueue_enqueue(que->tq, &que->que_task); | ||||
else | else | ||||
ixgbe_enable_queue(adapter, que->msix); | ixgbe_enable_queue(adapter, que->msix); | ||||
return; | return; | ||||
} | } /* ixgbe_msix_que */ | ||||
/************************************************************************ | |||||
* ixgbe_msix_link - Link status change ISR (MSI/MSI-X) | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_msix_link(void *arg) | ixgbe_msix_link(void *arg) | ||||
{ | { | ||||
struct adapter *adapter = arg; | struct adapter *adapter = arg; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 reg_eicr, mod_mask; | u32 eicr, eicr_mask; | ||||
++adapter->link_irq; | ++adapter->link_irq; | ||||
/* Pause other interrupts */ | /* Pause other interrupts */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER); | IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_OTHER); | ||||
/* First get the cause */ | /* First get the cause */ | ||||
reg_eicr = IXGBE_READ_REG(hw, IXGBE_EICS); | eicr = IXGBE_READ_REG(hw, IXGBE_EICS); | ||||
/* Be sure the queue bits are not cleared */ | /* Be sure the queue bits are not cleared */ | ||||
reg_eicr &= ~IXGBE_EICR_RTX_QUEUE; | eicr &= ~IXGBE_EICR_RTX_QUEUE; | ||||
/* Clear interrupt with write */ | /* Clear interrupt with write */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, reg_eicr); | IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr); | ||||
/* Link status change */ | /* Link status change */ | ||||
if (reg_eicr & IXGBE_EICR_LSC) { | if (eicr & IXGBE_EICR_LSC) { | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); | IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); | ||||
taskqueue_enqueue(adapter->tq, &adapter->link_task); | taskqueue_enqueue(adapter->tq, &adapter->link_task); | ||||
} | } | ||||
if (adapter->hw.mac.type != ixgbe_mac_82598EB) { | if (adapter->hw.mac.type != ixgbe_mac_82598EB) { | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
if (reg_eicr & IXGBE_EICR_FLOW_DIR) { | if (eicr & IXGBE_EICR_FLOW_DIR) { | ||||
/* This is probably overkill :) */ | /* This is probably overkill :) */ | ||||
if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) | if (!atomic_cmpset_int(&adapter->fdir_reinit, 0, 1)) | ||||
return; | return; | ||||
/* Disable the interrupt */ | /* Disable the interrupt */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_FLOW_DIR); | IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR); | ||||
taskqueue_enqueue(adapter->tq, &adapter->fdir_task); | taskqueue_enqueue(adapter->tq, &adapter->fdir_task); | ||||
} else | } else | ||||
#endif | #endif | ||||
if (reg_eicr & IXGBE_EICR_ECC) { | if (eicr & IXGBE_EICR_ECC) { | ||||
device_printf(adapter->dev, "CRITICAL: ECC ERROR!! " | device_printf(adapter->dev, | ||||
"Please Reboot!!\n"); | "CRITICAL: ECC ERROR!! Please Reboot!!\n"); | ||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); | IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); | ||||
} | } | ||||
/* Check for over temp condition */ | /* Check for over temp condition */ | ||||
if (reg_eicr & IXGBE_EICR_TS) { | if (eicr & IXGBE_EICR_TS) { | ||||
device_printf(adapter->dev, "CRITICAL: OVER TEMP!! " | device_printf(adapter->dev, | ||||
"PHY IS SHUT DOWN!!\n"); | "CRITICAL: OVER TEMP!! PHY IS SHUT DOWN!!\n"); | ||||
device_printf(adapter->dev, "System shutdown required!\n"); | device_printf(adapter->dev, | ||||
"System shutdown required!\n"); | |||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); | IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_TS); | ||||
} | } | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
if (reg_eicr & IXGBE_EICR_MAILBOX) | if (eicr & IXGBE_EICR_MAILBOX) | ||||
taskqueue_enqueue(adapter->tq, &adapter->mbx_task); | taskqueue_enqueue(adapter->tq, &adapter->mbx_task); | ||||
#endif | #endif | ||||
} | } | ||||
/* Pluggable optics-related interrupt */ | /* Pluggable optics-related interrupt */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) | ||||
mod_mask = IXGBE_EICR_GPI_SDP0_X540; | eicr_mask = IXGBE_EICR_GPI_SDP0_X540; | ||||
else | else | ||||
mod_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); | eicr_mask = IXGBE_EICR_GPI_SDP2_BY_MAC(hw); | ||||
if (ixgbe_is_sfp(hw)) { | if (ixgbe_is_sfp(hw)) { | ||||
if (reg_eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) { | if (eicr & IXGBE_EICR_GPI_SDP1_BY_MAC(hw)) { | ||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); | IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1_BY_MAC(hw)); | ||||
taskqueue_enqueue(adapter->tq, &adapter->msf_task); | taskqueue_enqueue(adapter->tq, &adapter->msf_task); | ||||
} else if (reg_eicr & mod_mask) { | } else if (eicr & eicr_mask) { | ||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, mod_mask); | IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask); | ||||
taskqueue_enqueue(adapter->tq, &adapter->mod_task); | taskqueue_enqueue(adapter->tq, &adapter->mod_task); | ||||
} | } | ||||
} | } | ||||
/* Check for fan failure */ | /* Check for fan failure */ | ||||
if ((hw->device_id == IXGBE_DEV_ID_82598AT) && | if ((hw->device_id == IXGBE_DEV_ID_82598AT) && | ||||
(reg_eicr & IXGBE_EICR_GPI_SDP1)) { | (eicr & IXGBE_EICR_GPI_SDP1)) { | ||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); | IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); | ||||
device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " | device_printf(adapter->dev, "\nCRITICAL: FAN FAILURE!! " | ||||
"REPLACE IMMEDIATELY!!\n"); | "REPLACE IMMEDIATELY!!\n"); | ||||
} | } | ||||
/* External PHY interrupt */ | /* External PHY interrupt */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && | ||||
(reg_eicr & IXGBE_EICR_GPI_SDP0_X540)) { | (eicr & IXGBE_EICR_GPI_SDP0_X540)) { | ||||
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); | IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0_X540); | ||||
taskqueue_enqueue(adapter->tq, &adapter->phy_task); | taskqueue_enqueue(adapter->tq, &adapter->phy_task); | ||||
} | } | ||||
/* Re-enable other interrupts */ | /* Re-enable other interrupts */ | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); | IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); | ||||
return; | return; | ||||
} | } /* ixgbe_msix_link */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* ixgbe_media_status - Media Ioctl callback | |||||
* | * | ||||
* Media Ioctl callback | * Called whenever the user queries the status of | ||||
* | |||||
* This routine is called whenever the user queries the status of | |||||
* the interface using ifconfig. | * the interface using ifconfig. | ||||
* | ************************************************************************/ | ||||
**********************************************************************/ | |||||
static void | static void | ||||
ixgbe_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) | ixgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) | ||||
{ | { | ||||
struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = ifp->if_softc; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
int layer; | int layer; | ||||
INIT_DEBUGOUT("ixgbe_media_status: begin"); | INIT_DEBUGOUT("ixgbe_media_status: begin"); | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
ixgbe_update_link_status(adapter); | ixgbe_update_link_status(adapter); | ||||
ifmr->ifm_status = IFM_AVALID; | ifmr->ifm_status = IFM_AVALID; | ||||
ifmr->ifm_active = IFM_ETHER; | ifmr->ifm_active = IFM_ETHER; | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR || | ||||
} | } | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) | ||||
switch (adapter->link_speed) { | switch (adapter->link_speed) { | ||||
case IXGBE_LINK_SPEED_10GB_FULL: | case IXGBE_LINK_SPEED_10GB_FULL: | ||||
ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; | ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; | ||||
break; | break; | ||||
} | } | ||||
/* | /* | ||||
** XXX: These need to use the proper media types once | * XXX: These need to use the proper media types once | ||||
** they're added. | * they're added. | ||||
*/ | */ | ||||
#ifndef IFM_ETH_XTYPE | #ifndef IFM_ETH_XTYPE | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) | ||||
switch (adapter->link_speed) { | switch (adapter->link_speed) { | ||||
case IXGBE_LINK_SPEED_10GB_FULL: | case IXGBE_LINK_SPEED_10GB_FULL: | ||||
ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; | ifmr->ifm_active |= IFM_10G_SR | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_2_5GB_FULL: | case IXGBE_LINK_SPEED_2_5GB_FULL: | ||||
ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; | ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_1GB_FULL: | case IXGBE_LINK_SPEED_1GB_FULL: | ||||
ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; | ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; | ||||
break; | break; | ||||
} | } | ||||
else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 || | ||||
|| layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) | layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) | ||||
switch (adapter->link_speed) { | switch (adapter->link_speed) { | ||||
case IXGBE_LINK_SPEED_10GB_FULL: | case IXGBE_LINK_SPEED_10GB_FULL: | ||||
ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; | ifmr->ifm_active |= IFM_10G_CX4 | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_2_5GB_FULL: | case IXGBE_LINK_SPEED_2_5GB_FULL: | ||||
ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; | ifmr->ifm_active |= IFM_2500_SX | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_1GB_FULL: | case IXGBE_LINK_SPEED_1GB_FULL: | ||||
ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; | ifmr->ifm_active |= IFM_1000_CX | IFM_FDX; | ||||
break; | break; | ||||
} | } | ||||
#else | #else | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) | ||||
switch (adapter->link_speed) { | switch (adapter->link_speed) { | ||||
case IXGBE_LINK_SPEED_10GB_FULL: | case IXGBE_LINK_SPEED_10GB_FULL: | ||||
ifmr->ifm_active |= IFM_10G_KR | IFM_FDX; | ifmr->ifm_active |= IFM_10G_KR | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_2_5GB_FULL: | case IXGBE_LINK_SPEED_2_5GB_FULL: | ||||
ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; | ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_1GB_FULL: | case IXGBE_LINK_SPEED_1GB_FULL: | ||||
ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; | ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; | ||||
break; | break; | ||||
} | } | ||||
else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | else if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KX4 || | ||||
|| layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) | layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) | ||||
switch (adapter->link_speed) { | switch (adapter->link_speed) { | ||||
case IXGBE_LINK_SPEED_10GB_FULL: | case IXGBE_LINK_SPEED_10GB_FULL: | ||||
ifmr->ifm_active |= IFM_10G_KX4 | IFM_FDX; | ifmr->ifm_active |= IFM_10G_KX4 | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_2_5GB_FULL: | case IXGBE_LINK_SPEED_2_5GB_FULL: | ||||
ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; | ifmr->ifm_active |= IFM_2500_KX | IFM_FDX; | ||||
break; | break; | ||||
case IXGBE_LINK_SPEED_1GB_FULL: | case IXGBE_LINK_SPEED_1GB_FULL: | ||||
ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; | ifmr->ifm_active |= IFM_1000_KX | IFM_FDX; | ||||
break; | break; | ||||
} | } | ||||
#endif | #endif | ||||
/* If nothing is recognized... */ | /* If nothing is recognized... */ | ||||
if (IFM_SUBTYPE(ifmr->ifm_active) == 0) | if (IFM_SUBTYPE(ifmr->ifm_active) == 0) | ||||
ifmr->ifm_active |= IFM_UNKNOWN; | ifmr->ifm_active |= IFM_UNKNOWN; | ||||
#if __FreeBSD_version >= 900025 | #if __FreeBSD_version >= 900025 | ||||
/* Display current flow control setting used on link */ | /* Display current flow control setting used on link */ | ||||
if (hw->fc.current_mode == ixgbe_fc_rx_pause || | if (hw->fc.current_mode == ixgbe_fc_rx_pause || | ||||
hw->fc.current_mode == ixgbe_fc_full) | hw->fc.current_mode == ixgbe_fc_full) | ||||
ifmr->ifm_active |= IFM_ETH_RXPAUSE; | ifmr->ifm_active |= IFM_ETH_RXPAUSE; | ||||
if (hw->fc.current_mode == ixgbe_fc_tx_pause || | if (hw->fc.current_mode == ixgbe_fc_tx_pause || | ||||
hw->fc.current_mode == ixgbe_fc_full) | hw->fc.current_mode == ixgbe_fc_full) | ||||
ifmr->ifm_active |= IFM_ETH_TXPAUSE; | ifmr->ifm_active |= IFM_ETH_TXPAUSE; | ||||
#endif | #endif | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
return; | return; | ||||
} | } /* ixgbe_media_status */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* ixgbe_media_change - Media Ioctl callback | |||||
* | * | ||||
* Media Ioctl callback | * Called when the user changes speed/duplex using | ||||
* | |||||
* This routine is called when the user changes speed/duplex using | |||||
* media/mediopt option with ifconfig. | * media/mediopt option with ifconfig. | ||||
* | ************************************************************************/ | ||||
**********************************************************************/ | |||||
static int | static int | ||||
ixgbe_media_change(struct ifnet * ifp) | ixgbe_media_change(struct ifnet *ifp) | ||||
{ | { | ||||
struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = ifp->if_softc; | ||||
struct ifmedia *ifm = &adapter->media; | struct ifmedia *ifm = &adapter->media; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
ixgbe_link_speed speed = 0; | ixgbe_link_speed speed = 0; | ||||
INIT_DEBUGOUT("ixgbe_media_change: begin"); | INIT_DEBUGOUT("ixgbe_media_change: begin"); | ||||
if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) | if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (hw->phy.media_type == ixgbe_media_type_backplane) | if (hw->phy.media_type == ixgbe_media_type_backplane) | ||||
return (ENODEV); | return (ENODEV); | ||||
/* | /* | ||||
** We don't actually need to check against the supported | * We don't actually need to check against the supported | ||||
** media types of the adapter; ifmedia will take care of | * media types of the adapter; ifmedia will take care of | ||||
** that for us. | * that for us. | ||||
*/ | */ | ||||
#ifndef IFM_ETH_XTYPE | #ifndef IFM_ETH_XTYPE | ||||
switch (IFM_SUBTYPE(ifm->ifm_media)) { | switch (IFM_SUBTYPE(ifm->ifm_media)) { | ||||
case IFM_AUTO: | case IFM_AUTO: | ||||
case IFM_10G_T: | case IFM_10G_T: | ||||
speed |= IXGBE_LINK_SPEED_100_FULL; | speed |= IXGBE_LINK_SPEED_100_FULL; | ||||
case IFM_10G_LRM: | case IFM_10G_LRM: | ||||
case IFM_10G_SR: /* KR, too */ | case IFM_10G_SR: /* KR, too */ | ||||
case IFM_10G_LR: | case IFM_10G_LR: | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | #else | ||||
} | } | ||||
#endif | #endif | ||||
hw->mac.autotry_restart = TRUE; | hw->mac.autotry_restart = TRUE; | ||||
hw->mac.ops.setup_link(hw, speed, TRUE); | hw->mac.ops.setup_link(hw, speed, TRUE); | ||||
if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { | if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { | ||||
adapter->advertise = 0; | adapter->advertise = 0; | ||||
} else { | } else { | ||||
if ((speed & IXGBE_LINK_SPEED_10GB_FULL) != 0) | if (speed & IXGBE_LINK_SPEED_10GB_FULL) | ||||
adapter->advertise |= 1 << 2; | adapter->advertise |= 1 << 2; | ||||
if ((speed & IXGBE_LINK_SPEED_1GB_FULL) != 0) | if (speed & IXGBE_LINK_SPEED_1GB_FULL) | ||||
adapter->advertise |= 1 << 1; | adapter->advertise |= 1 << 1; | ||||
if ((speed & IXGBE_LINK_SPEED_100_FULL) != 0) | if (speed & IXGBE_LINK_SPEED_100_FULL) | ||||
adapter->advertise |= 1 << 0; | adapter->advertise |= 1 << 0; | ||||
} | } | ||||
return (0); | return (0); | ||||
invalid: | invalid: | ||||
device_printf(adapter->dev, "Invalid media type!\n"); | device_printf(adapter->dev, "Invalid media type!\n"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } /* ixgbe_media_change */ | ||||
/************************************************************************ | |||||
* ixgbe_set_promisc | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_set_promisc(struct adapter *adapter) | ixgbe_set_promisc(struct adapter *adapter) | ||||
{ | { | ||||
u_int32_t reg_rctl; | |||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
int mcnt = 0; | int mcnt = 0; | ||||
u32 rctl; | |||||
reg_rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); | rctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL); | ||||
reg_rctl &= (~IXGBE_FCTRL_UPE); | rctl &= (~IXGBE_FCTRL_UPE); | ||||
if (ifp->if_flags & IFF_ALLMULTI) | if (ifp->if_flags & IFF_ALLMULTI) | ||||
mcnt = MAX_NUM_MULTICAST_ADDRESSES; | mcnt = MAX_NUM_MULTICAST_ADDRESSES; | ||||
else { | else { | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
#if __FreeBSD_version < 800000 | #if __FreeBSD_version < 800000 | ||||
IF_ADDR_LOCK(ifp); | IF_ADDR_LOCK(ifp); | ||||
#else | #else | ||||
if_maddr_rlock(ifp); | if_maddr_rlock(ifp); | ||||
#endif | #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; | ||||
if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) | if (mcnt == MAX_NUM_MULTICAST_ADDRESSES) | ||||
break; | break; | ||||
mcnt++; | mcnt++; | ||||
} | } | ||||
#if __FreeBSD_version < 800000 | #if __FreeBSD_version < 800000 | ||||
IF_ADDR_UNLOCK(ifp); | IF_ADDR_UNLOCK(ifp); | ||||
#else | #else | ||||
if_maddr_runlock(ifp); | if_maddr_runlock(ifp); | ||||
#endif | #endif | ||||
} | } | ||||
if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) | if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) | ||||
reg_rctl &= (~IXGBE_FCTRL_MPE); | rctl &= (~IXGBE_FCTRL_MPE); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, rctl); | ||||
if (ifp->if_flags & IFF_PROMISC) { | if (ifp->if_flags & IFF_PROMISC) { | ||||
reg_rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | rctl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, rctl); | ||||
} else if (ifp->if_flags & IFF_ALLMULTI) { | } else if (ifp->if_flags & IFF_ALLMULTI) { | ||||
reg_rctl |= IXGBE_FCTRL_MPE; | rctl |= IXGBE_FCTRL_MPE; | ||||
reg_rctl &= ~IXGBE_FCTRL_UPE; | rctl &= ~IXGBE_FCTRL_UPE; | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, reg_rctl); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, rctl); | ||||
} | } | ||||
return; | return; | ||||
} | } /* ixgbe_set_promisc */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* Multicast Update | * ixgbe_set_multi - Multicast Update | ||||
* | * | ||||
* This routine is called whenever multicast address list is updated. | * Called whenever multicast address list is updated. | ||||
* | ************************************************************************/ | ||||
**********************************************************************/ | |||||
#define IXGBE_RAR_ENTRIES 16 | #define IXGBE_RAR_ENTRIES 16 | ||||
static void | static void | ||||
ixgbe_set_multi(struct adapter *adapter) | ixgbe_set_multi(struct adapter *adapter) | ||||
{ | { | ||||
u32 fctrl; | |||||
u8 *update_ptr; | |||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
struct ixgbe_mc_addr *mta; | struct ixgbe_mc_addr *mta; | ||||
int mcnt = 0; | |||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
u8 *update_ptr; | |||||
int mcnt = 0; | |||||
u32 fctrl; | |||||
IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); | IOCTL_DEBUGOUT("ixgbe_set_multi: begin"); | ||||
mta = adapter->mta; | mta = adapter->mta; | ||||
bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); | bzero(mta, sizeof(*mta) * MAX_NUM_MULTICAST_ADDRESSES); | ||||
#if __FreeBSD_version < 800000 | #if __FreeBSD_version < 800000 | ||||
IF_ADDR_LOCK(ifp); | IF_ADDR_LOCK(ifp); | ||||
Show All 21 Lines | #endif | ||||
if (ifp->if_flags & IFF_PROMISC) | if (ifp->if_flags & IFF_PROMISC) | ||||
fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | ||||
else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || | else if (mcnt >= MAX_NUM_MULTICAST_ADDRESSES || | ||||
ifp->if_flags & IFF_ALLMULTI) { | ifp->if_flags & IFF_ALLMULTI) { | ||||
fctrl |= IXGBE_FCTRL_MPE; | fctrl |= IXGBE_FCTRL_MPE; | ||||
fctrl &= ~IXGBE_FCTRL_UPE; | fctrl &= ~IXGBE_FCTRL_UPE; | ||||
} else | } else | ||||
fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl); | ||||
if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { | if (mcnt < MAX_NUM_MULTICAST_ADDRESSES) { | ||||
update_ptr = (u8 *)mta; | update_ptr = (u8 *)mta; | ||||
ixgbe_update_mc_addr_list(&adapter->hw, | ixgbe_update_mc_addr_list(&adapter->hw, update_ptr, mcnt, | ||||
update_ptr, mcnt, ixgbe_mc_array_itr, TRUE); | ixgbe_mc_array_itr, TRUE); | ||||
} | } | ||||
return; | return; | ||||
} | } /* ixgbe_set_multi */ | ||||
/* | /************************************************************************ | ||||
* This is an iterator function now needed by the multicast | * ixgbe_mc_array_itr | ||||
* shared code. It simply feeds the shared code routine the | * | ||||
* addresses in the array of ixgbe_set_multi() one by one. | * An iterator function needed by the multicast shared code. | ||||
*/ | * It feeds the shared code routine the addresses in the | ||||
* array of ixgbe_set_multi() one by one. | |||||
************************************************************************/ | |||||
static u8 * | static u8 * | ||||
ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) | ixgbe_mc_array_itr(struct ixgbe_hw *hw, u8 **update_ptr, u32 *vmdq) | ||||
{ | { | ||||
struct ixgbe_mc_addr *mta; | struct ixgbe_mc_addr *mta; | ||||
mta = (struct ixgbe_mc_addr *)*update_ptr; | mta = (struct ixgbe_mc_addr *)*update_ptr; | ||||
*vmdq = mta->vmdq; | *vmdq = mta->vmdq; | ||||
*update_ptr = (u8*)(mta + 1); | *update_ptr = (u8*)(mta + 1); | ||||
return (mta->addr); | return (mta->addr); | ||||
} | } /* ixgbe_mc_array_itr */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* Timer routine | * ixgbe_local_timer - Timer routine | ||||
* | * | ||||
* This 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 | ||||
ixgbe_local_timer(void *arg) | ixgbe_local_timer(void *arg) | ||||
{ | { | ||||
struct adapter *adapter = arg; | struct adapter *adapter = arg; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
struct ix_queue *que = adapter->queues; | struct ix_queue *que = adapter->queues; | ||||
u64 queues = 0; | u64 queues = 0; | ||||
int hung = 0; | int hung = 0; | ||||
mtx_assert(&adapter->core_mtx, MA_OWNED); | mtx_assert(&adapter->core_mtx, MA_OWNED); | ||||
/* Check for pluggable optics */ | /* Check for pluggable optics */ | ||||
if (adapter->sfp_probe) | if (adapter->sfp_probe) | ||||
if (!ixgbe_sfp_probe(adapter)) | if (!ixgbe_sfp_probe(adapter)) | ||||
goto out; /* Nothing to do */ | goto out; /* Nothing to do */ | ||||
ixgbe_update_link_status(adapter); | ixgbe_update_link_status(adapter); | ||||
ixgbe_update_stats_counters(adapter); | ixgbe_update_stats_counters(adapter); | ||||
/* | /* | ||||
** Check the TX queues status | * Check the TX queues status | ||||
** - mark hung queues so we don't schedule on them | * - mark hung queues so we don't schedule on them | ||||
** - watchdog only if all queues show hung | * - watchdog only if all queues show hung | ||||
*/ | */ | ||||
for (int i = 0; i < adapter->num_queues; i++, que++) { | for (int i = 0; i < adapter->num_queues; i++, que++) { | ||||
/* Keep track of queues with work for soft irq */ | /* Keep track of queues with work for soft irq */ | ||||
if (que->txr->busy) | if (que->txr->busy) | ||||
queues |= ((u64)1 << que->me); | queues |= ((u64)1 << que->me); | ||||
/* | /* | ||||
** Each time txeof runs without cleaning, but there | * Each time txeof runs without cleaning, but there | ||||
** are uncleaned descriptors it increments busy. If | * are uncleaned descriptors it increments busy. If | ||||
** we get to the MAX we declare it hung. | * we get to the MAX we declare it hung. | ||||
*/ | */ | ||||
if (que->busy == IXGBE_QUEUE_HUNG) { | if (que->busy == IXGBE_QUEUE_HUNG) { | ||||
++hung; | ++hung; | ||||
/* Mark the queue as inactive */ | /* Mark the queue as inactive */ | ||||
adapter->active_queues &= ~((u64)1 << que->me); | adapter->active_queues &= ~((u64)1 << que->me); | ||||
continue; | continue; | ||||
} else { | } else { | ||||
/* Check if we've come back from hung */ | /* Check if we've come back from hung */ | ||||
if ((adapter->active_queues & ((u64)1 << que->me)) == 0) | if ((adapter->active_queues & ((u64)1 << que->me)) == 0) | ||||
adapter->active_queues |= ((u64)1 << que->me); | adapter->active_queues |= ((u64)1 << que->me); | ||||
} | } | ||||
if (que->busy >= IXGBE_MAX_TX_BUSY) { | if (que->busy >= IXGBE_MAX_TX_BUSY) { | ||||
device_printf(dev,"Warning queue %d " | device_printf(dev, | ||||
"appears to be hung!\n", i); | "Warning queue %d appears to be hung!\n", i); | ||||
que->txr->busy = IXGBE_QUEUE_HUNG; | que->txr->busy = IXGBE_QUEUE_HUNG; | ||||
++hung; | ++hung; | ||||
} | } | ||||
} | } | ||||
/* Only truly watchdog if all queues show hung */ | /* Only truly watchdog if all queues show hung */ | ||||
if (hung == adapter->num_queues) | if (hung == adapter->num_queues) | ||||
goto watchdog; | goto watchdog; | ||||
else if (queues != 0) { /* Force an IRQ on queues with work */ | else if (queues != 0) { /* Force an IRQ on queues with work */ | ||||
ixgbe_rearm_queues(adapter, queues); | ixgbe_rearm_queues(adapter, queues); | ||||
} | } | ||||
out: | out: | ||||
callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); | callout_reset(&adapter->timer, hz, ixgbe_local_timer, adapter); | ||||
return; | return; | ||||
watchdog: | watchdog: | ||||
device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); | device_printf(adapter->dev, "Watchdog timeout -- resetting\n"); | ||||
adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | adapter->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | ||||
adapter->watchdog_events++; | adapter->watchdog_events++; | ||||
ixgbe_init_locked(adapter); | ixgbe_init_locked(adapter); | ||||
} | } /* ixgbe_local_timer */ | ||||
/* | /************************************************************************ | ||||
** Note: this routine updates the OS on the link state | * ixgbe_update_link_status - Update OS on link state | ||||
** the real check of the hardware only happens with | * | ||||
** a link interrupt. | * Note: Only updates the OS on the cached link state. | ||||
*/ | * The real check of the hardware only happens with | ||||
* a link interrupt. | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_update_link_status(struct adapter *adapter) | ixgbe_update_link_status(struct adapter *adapter) | ||||
{ | { | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
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; | ||||
/* Update any Flow Control changes */ | /* Update any Flow Control changes */ | ||||
ixgbe_fc_enable(&adapter->hw); | ixgbe_fc_enable(&adapter->hw); | ||||
/* Update DMA coalescing config */ | /* Update DMA coalescing config */ | ||||
ixgbe_config_dmac(adapter); | ixgbe_config_dmac(adapter); | ||||
if_link_state_change(ifp, LINK_STATE_UP); | if_link_state_change(ifp, LINK_STATE_UP); | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
ixgbe_ping_all_vfs(adapter); | ixgbe_ping_all_vfs(adapter); | ||||
#endif | #endif | ||||
} | } | ||||
} 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); | if_link_state_change(ifp, LINK_STATE_DOWN); | ||||
adapter->link_active = FALSE; | adapter->link_active = FALSE; | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
ixgbe_ping_all_vfs(adapter); | ixgbe_ping_all_vfs(adapter); | ||||
#endif | #endif | ||||
} | } | ||||
} | } | ||||
return; | return; | ||||
} | } /* ixgbe_update_link_status */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* ixgbe_stop - Stop the hardware | |||||
* | * | ||||
* This routine 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 | ||||
ixgbe_stop(void *arg) | ixgbe_stop(void *arg) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct adapter *adapter = arg; | struct adapter *adapter = arg; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
ifp = adapter->ifp; | ifp = adapter->ifp; | ||||
mtx_assert(&adapter->core_mtx, MA_OWNED); | mtx_assert(&adapter->core_mtx, MA_OWNED); | ||||
INIT_DEBUGOUT("ixgbe_stop: begin\n"); | INIT_DEBUGOUT("ixgbe_stop: begin\n"); | ||||
ixgbe_disable_intr(adapter); | ixgbe_disable_intr(adapter); | ||||
callout_stop(&adapter->timer); | callout_stop(&adapter->timer); | ||||
/* Let the stack know...*/ | /* Let the stack know...*/ | ||||
ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | ifp->if_drv_flags &= ~IFF_DRV_RUNNING; | ||||
ixgbe_reset_hw(hw); | ixgbe_reset_hw(hw); | ||||
hw->adapter_stopped = FALSE; | hw->adapter_stopped = FALSE; | ||||
ixgbe_stop_adapter(hw); | ixgbe_stop_adapter(hw); | ||||
if (hw->mac.type == ixgbe_mac_82599EB) | if (hw->mac.type == ixgbe_mac_82599EB) | ||||
ixgbe_stop_mac_link_on_d3_82599(hw); | ixgbe_stop_mac_link_on_d3_82599(hw); | ||||
/* Turn off the laser - noop with no optics */ | /* Turn off the laser - noop with no optics */ | ||||
ixgbe_disable_tx_laser(hw); | ixgbe_disable_tx_laser(hw); | ||||
/* Update the stack */ | /* Update the stack */ | ||||
adapter->link_up = FALSE; | adapter->link_up = FALSE; | ||||
ixgbe_update_link_status(adapter); | ixgbe_update_link_status(adapter); | ||||
/* reprogram the RAR[0] in case user changed it. */ | /* reprogram the RAR[0] in case user changed it. */ | ||||
ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); | ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV); | ||||
return; | return; | ||||
} | } /* ixgbe_stop */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * | ||||
* Determine hardware revision. | * Determine hardware revision. | ||||
* | * | ||||
**********************************************************************/ | ************************************************************************/ | ||||
static void | static void | ||||
ixgbe_identify_hardware(struct adapter *adapter) | ixgbe_identify_hardware(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; | ||||
/* Save off the information about this board */ | /* Save off the information about this board */ | ||||
hw->vendor_id = pci_get_vendor(dev); | hw->vendor_id = pci_get_vendor(dev); | ||||
Show All 17 Lines | if (hw->mac.type != ixgbe_mac_82598EB) { | ||||
hw->phy.smart_speed = ixgbe_smart_speed; | hw->phy.smart_speed = ixgbe_smart_speed; | ||||
adapter->num_segs = IXGBE_82599_SCATTER; | adapter->num_segs = IXGBE_82599_SCATTER; | ||||
} else | } else | ||||
adapter->num_segs = IXGBE_82598_SCATTER; | adapter->num_segs = IXGBE_82598_SCATTER; | ||||
return; | return; | ||||
} | } | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * | ||||
* Determine optic type | * Determine optic type | ||||
* | * | ||||
**********************************************************************/ | ************************************************************************/ | ||||
static void | static void | ||||
ixgbe_setup_optics(struct adapter *adapter) | ixgbe_setup_optics(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
int layer; | int layer; | ||||
layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); | layer = adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); | ||||
Show All 34 Lines | if (layer & (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 | | ||||
return; | return; | ||||
} | } | ||||
/* If we get here just set the default */ | /* If we get here just set the default */ | ||||
adapter->optics = IFM_ETHER | IFM_AUTO; | adapter->optics = IFM_ETHER | IFM_AUTO; | ||||
return; | return; | ||||
} | } | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * ixgbe_allocate_legacy - Setup the Legacy or MSI Interrupt handler | ||||
* Setup the Legacy or MSI Interrupt handler | ************************************************************************/ | ||||
* | |||||
**********************************************************************/ | |||||
static int | static int | ||||
ixgbe_allocate_legacy(struct adapter *adapter) | ixgbe_allocate_legacy(struct adapter *adapter) | ||||
{ | { | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
struct ix_queue *que = adapter->queues; | struct ix_queue *que = adapter->queues; | ||||
#ifndef IXGBE_LEGACY_TX | #ifndef IXGBE_LEGACY_TX | ||||
struct tx_ring *txr = adapter->tx_rings; | struct tx_ring *txr = adapter->tx_rings; | ||||
#endif | #endif | ||||
int error, rid = 0; | int error, rid = 0; | ||||
/* MSI RID at 1 */ | /* MSI RID at 1 */ | ||||
if (adapter->msix == 1) | if (adapter->msix == 1) | ||||
rid = 1; | rid = 1; | ||||
/* We allocate a single interrupt resource */ | /* We allocate a single interrupt resource */ | ||||
adapter->res = bus_alloc_resource_any(dev, | adapter->res = bus_alloc_resource_any(dev, | ||||
SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); | SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); | ||||
if (adapter->res == NULL) { | if (adapter->res == NULL) { | ||||
device_printf(dev, "Unable to allocate bus resource: " | device_printf(dev, | ||||
"interrupt\n"); | "Unable to allocate bus resource: interrupt\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* | /* | ||||
* Try allocating a fast interrupt and the associated deferred | * Try allocating a fast interrupt and the associated deferred | ||||
* processing contexts. | * processing contexts. | ||||
*/ | */ | ||||
#ifndef IXGBE_LEGACY_TX | #ifndef IXGBE_LEGACY_TX | ||||
TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); | TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); | ||||
#endif | #endif | ||||
TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); | TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); | ||||
que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, | que->tq = taskqueue_create_fast("ixgbe_que", M_NOWAIT, | ||||
taskqueue_thread_enqueue, &que->tq); | taskqueue_thread_enqueue, &que->tq); | ||||
taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq", | taskqueue_start_threads(&que->tq, 1, PI_NET, "%s ixq", | ||||
device_get_nameunit(adapter->dev)); | device_get_nameunit(adapter->dev)); | ||||
/* Tasklets for Link, SFP and Multispeed Fiber */ | /* Tasklets for Link, SFP and Multispeed Fiber */ | ||||
TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); | TASK_INIT(&adapter->link_task, 0, ixgbe_handle_link, adapter); | ||||
TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); | TASK_INIT(&adapter->mod_task, 0, ixgbe_handle_mod, adapter); | ||||
TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); | TASK_INIT(&adapter->msf_task, 0, ixgbe_handle_msf, adapter); | ||||
TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); | TASK_INIT(&adapter->phy_task, 0, ixgbe_handle_phy, adapter); | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); | TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); | ||||
#endif | #endif | ||||
adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, | adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, | ||||
taskqueue_thread_enqueue, &adapter->tq); | taskqueue_thread_enqueue, &adapter->tq); | ||||
taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", | taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", | ||||
device_get_nameunit(adapter->dev)); | device_get_nameunit(adapter->dev)); | ||||
if ((error = bus_setup_intr(dev, adapter->res, | if ((error = bus_setup_intr(dev, adapter->res, | ||||
INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, | INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_legacy_irq, que, | ||||
que, &adapter->tag)) != 0) { | &adapter->tag)) != 0) { | ||||
device_printf(dev, "Failed to register fast interrupt " | device_printf(dev, | ||||
"handler: %d\n", error); | "Failed to register fast interrupt handler: %d\n", error); | ||||
taskqueue_free(que->tq); | taskqueue_free(que->tq); | ||||
taskqueue_free(adapter->tq); | taskqueue_free(adapter->tq); | ||||
que->tq = NULL; | que->tq = NULL; | ||||
adapter->tq = NULL; | adapter->tq = NULL; | ||||
return (error); | return (error); | ||||
} | } | ||||
/* For simplicity in the handlers */ | /* For simplicity in the handlers */ | ||||
adapter->active_queues = IXGBE_EIMS_ENABLE_MASK; | adapter->active_queues = IXGBE_EIMS_ENABLE_MASK; | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_allocate_legacy */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * ixgbe_allocate_msix - Setup MSI-X Interrupt resources and handlers | ||||
* Setup MSIX Interrupt resources and handlers | ************************************************************************/ | ||||
* | |||||
**********************************************************************/ | |||||
static int | static int | ||||
ixgbe_allocate_msix(struct adapter *adapter) | ixgbe_allocate_msix(struct adapter *adapter) | ||||
{ | { | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
struct ix_queue *que = adapter->queues; | struct ix_queue *que = adapter->queues; | ||||
struct tx_ring *txr = adapter->tx_rings; | struct tx_ring *txr = adapter->tx_rings; | ||||
int error, rid, vector = 0; | int error, rid, vector = 0; | ||||
int cpu_id = 0; | int cpu_id = 0; | ||||
#ifdef RSS | #ifdef RSS | ||||
cpuset_t cpu_mask; | cpuset_t cpu_mask; | ||||
#endif | #endif | ||||
#ifdef RSS | #ifdef RSS | ||||
/* | /* | ||||
* If we're doing RSS, the number of queues needs to | * If we're doing RSS, the number of queues needs to | ||||
* match the number of RSS buckets that are configured. | * match the number of RSS buckets that are configured. | ||||
* | * | ||||
* + If there's more queues than RSS buckets, we'll end | * + If there's more queues than RSS buckets, we'll end | ||||
Show All 13 Lines | #ifdef RSS | ||||
} | } | ||||
#endif | #endif | ||||
for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { | for (int i = 0; i < adapter->num_queues; i++, vector++, que++, txr++) { | ||||
rid = vector + 1; | rid = vector + 1; | ||||
que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | que->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, | ||||
RF_SHAREABLE | RF_ACTIVE); | RF_SHAREABLE | RF_ACTIVE); | ||||
if (que->res == NULL) { | if (que->res == NULL) { | ||||
device_printf(dev,"Unable to allocate" | device_printf(dev, "Unable to allocate bus resource: que interrupt [%d]\n", | ||||
" bus resource: que interrupt [%d]\n", vector); | vector); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* Set the handler function */ | /* Set the handler function */ | ||||
error = bus_setup_intr(dev, que->res, | error = bus_setup_intr(dev, que->res, | ||||
INTR_TYPE_NET | INTR_MPSAFE, NULL, | INTR_TYPE_NET | INTR_MPSAFE, NULL, ixgbe_msix_que, que, | ||||
ixgbe_msix_que, que, &que->tag); | &que->tag); | ||||
if (error) { | if (error) { | ||||
que->res = NULL; | que->res = NULL; | ||||
device_printf(dev, "Failed to register QUE handler"); | device_printf(dev, "Failed to register QUE handler"); | ||||
return (error); | return (error); | ||||
} | } | ||||
#if __FreeBSD_version >= 800504 | #if __FreeBSD_version >= 800504 | ||||
bus_describe_intr(dev, que->res, que->tag, "q%d", i); | bus_describe_intr(dev, que->res, que->tag, "q%d", i); | ||||
#endif | #endif | ||||
Show All 16 Lines | #else | ||||
*/ | */ | ||||
if (adapter->num_queues > 1) | if (adapter->num_queues > 1) | ||||
cpu_id = i; | cpu_id = i; | ||||
#endif | #endif | ||||
if (adapter->num_queues > 1) | if (adapter->num_queues > 1) | ||||
bus_bind_intr(dev, que->res, cpu_id); | bus_bind_intr(dev, que->res, cpu_id); | ||||
#ifdef IXGBE_DEBUG | #ifdef IXGBE_DEBUG | ||||
#ifdef RSS | #ifdef RSS | ||||
device_printf(dev, | device_printf(dev, "Bound RSS bucket %d to CPU %d\n", i, | ||||
"Bound RSS bucket %d to CPU %d\n", | cpu_id); | ||||
i, cpu_id); | |||||
#else | #else | ||||
device_printf(dev, | device_printf(dev, "Bound queue %d to cpu %d\n", i, | ||||
"Bound queue %d to cpu %d\n", | cpu_id); | ||||
i, cpu_id); | |||||
#endif | #endif | ||||
#endif /* IXGBE_DEBUG */ | #endif /* IXGBE_DEBUG */ | ||||
#ifndef IXGBE_LEGACY_TX | #ifndef IXGBE_LEGACY_TX | ||||
TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); | TASK_INIT(&txr->txq_task, 0, ixgbe_deferred_mq_start, txr); | ||||
#endif | #endif | ||||
TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); | TASK_INIT(&que->que_task, 0, ixgbe_handle_que, que); | ||||
Show All 9 Lines | |||||
#else | #else | ||||
taskqueue_start_threads(&que->tq, 1, PI_NET, "%s:q%d", | taskqueue_start_threads(&que->tq, 1, PI_NET, "%s:q%d", | ||||
device_get_nameunit(adapter->dev), i); | device_get_nameunit(adapter->dev), i); | ||||
#endif | #endif | ||||
} | } | ||||
/* and Link */ | /* and Link */ | ||||
rid = vector + 1; | rid = vector + 1; | ||||
adapter->res = bus_alloc_resource_any(dev, | adapter->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, | ||||
SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); | &rid, RF_SHAREABLE | RF_ACTIVE); | ||||
if (!adapter->res) { | if (!adapter->res) { | ||||
device_printf(dev,"Unable to allocate" | device_printf(dev, | ||||
" bus resource: Link interrupt [%d]\n", rid); | "Unable to allocate bus resource: Link interrupt [%d]\n", | ||||
rid); | |||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* Set the link handler function */ | /* Set the link handler function */ | ||||
error = bus_setup_intr(dev, adapter->res, | error = bus_setup_intr(dev, adapter->res, INTR_TYPE_NET | INTR_MPSAFE, | ||||
INTR_TYPE_NET | INTR_MPSAFE, NULL, | NULL, ixgbe_msix_link, adapter, &adapter->tag); | ||||
ixgbe_msix_link, adapter, &adapter->tag); | |||||
if (error) { | if (error) { | ||||
adapter->res = NULL; | adapter->res = NULL; | ||||
device_printf(dev, "Failed to register LINK handler"); | device_printf(dev, "Failed to register LINK handler"); | ||||
return (error); | return (error); | ||||
} | } | ||||
#if __FreeBSD_version >= 800504 | #if __FreeBSD_version >= 800504 | ||||
bus_describe_intr(dev, adapter->res, adapter->tag, "link"); | bus_describe_intr(dev, adapter->res, adapter->tag, "link"); | ||||
#endif | #endif | ||||
Show All 10 Lines | #ifdef IXGBE_FDIR | ||||
TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); | TASK_INIT(&adapter->fdir_task, 0, ixgbe_reinit_fdir, adapter); | ||||
#endif | #endif | ||||
adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, | adapter->tq = taskqueue_create_fast("ixgbe_link", M_NOWAIT, | ||||
taskqueue_thread_enqueue, &adapter->tq); | taskqueue_thread_enqueue, &adapter->tq); | ||||
taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", | taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s linkq", | ||||
device_get_nameunit(adapter->dev)); | device_get_nameunit(adapter->dev)); | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_allocate_msix */ | ||||
/* | |||||
* Setup Either MSI/X or MSI | |||||
*/ | |||||
static int | static int | ||||
ixgbe_setup_msix(struct adapter *adapter) | ixgbe_setup_msix(struct adapter *adapter) | ||||
{ | { | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
int rid, want, queues, msgs; | int rid, want, queues, msgs; | ||||
/* Override by tuneable */ | /* Override by tuneable */ | ||||
if (ixgbe_enable_msix == 0) | if (ixgbe_enable_msix == 0) | ||||
goto msi; | goto msi; | ||||
/* First try MSI/X */ | /* First try MSI-X */ | ||||
msgs = pci_msix_count(dev); | msgs = pci_msix_count(dev); | ||||
if (msgs == 0) | if (msgs == 0) | ||||
goto msi; | goto msi; | ||||
rid = PCIR_BAR(MSIX_82598_BAR); | rid = PCIR_BAR(MSIX_82598_BAR); | ||||
adapter->msix_mem = bus_alloc_resource_any(dev, | adapter->msix_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | ||||
SYS_RES_MEMORY, &rid, RF_ACTIVE); | RF_ACTIVE); | ||||
if (adapter->msix_mem == NULL) { | if (adapter->msix_mem == NULL) { | ||||
rid += 4; /* 82599 maps in higher BAR */ | rid += 4; /* 82599 maps in higher BAR */ | ||||
adapter->msix_mem = bus_alloc_resource_any(dev, | adapter->msix_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | ||||
SYS_RES_MEMORY, &rid, RF_ACTIVE); | &rid, RF_ACTIVE); | ||||
} | } | ||||
if (adapter->msix_mem == NULL) { | if (adapter->msix_mem == NULL) { | ||||
/* May not be enabled */ | /* May not be enabled */ | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, "Unable to map MSI-X table.\n"); | ||||
"Unable to map MSIX table \n"); | |||||
goto msi; | goto msi; | ||||
} | } | ||||
/* Figure out a reasonable auto config value */ | /* Figure out a reasonable auto config value */ | ||||
queues = (mp_ncpus > (msgs - 1)) ? (msgs - 1) : mp_ncpus; | queues = (mp_ncpus > (msgs - 1)) ? (msgs - 1) : mp_ncpus; | ||||
#ifdef RSS | #ifdef RSS | ||||
/* If we're doing RSS, clamp at the number of RSS buckets */ | /* If we're doing RSS, clamp at the number of RSS buckets */ | ||||
if (queues > rss_getnumbuckets()) | if (queues > rss_getnumbuckets()) | ||||
queues = rss_getnumbuckets(); | queues = rss_getnumbuckets(); | ||||
#endif | #endif | ||||
if (ixgbe_num_queues != 0) | if (ixgbe_num_queues != 0) | ||||
queues = ixgbe_num_queues; | queues = ixgbe_num_queues; | ||||
/* Set max queues to 8 when autoconfiguring */ | /* Set max queues to 8 when autoconfiguring */ | ||||
else if ((ixgbe_num_queues == 0) && (queues > 8)) | else if ((ixgbe_num_queues == 0) && (queues > 8)) | ||||
queues = 8; | queues = 8; | ||||
/* reflect correct sysctl value */ | /* reflect correct sysctl value */ | ||||
ixgbe_num_queues = queues; | ixgbe_num_queues = queues; | ||||
/* | /* | ||||
** Want one vector (RX/TX pair) per queue | * Want one vector (RX/TX pair) per queue | ||||
** plus an additional for Link. | * plus an additional for Link. | ||||
*/ | */ | ||||
want = queues + 1; | want = queues + 1; | ||||
if (msgs >= want) | if (msgs >= want) | ||||
msgs = want; | msgs = want; | ||||
else { | else { | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, "MSI-X Configuration Problem, %d vectors but %d queues wanted!\n", | ||||
"MSIX Configuration Problem, " | |||||
"%d vectors but %d queues wanted!\n", | |||||
msgs, want); | msgs, want); | ||||
goto msi; | goto msi; | ||||
} | } | ||||
if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { | if ((pci_alloc_msix(dev, &msgs) == 0) && (msgs == want)) { | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Using MSIX interrupts with %d vectors\n", msgs); | "Using MSI-X interrupts with %d vectors\n", msgs); | ||||
adapter->num_queues = queues; | adapter->num_queues = queues; | ||||
return (msgs); | return (msgs); | ||||
} | } | ||||
/* | /* | ||||
** If MSIX alloc failed or provided us with | * MSI-X allocation failed or provided us with | ||||
** less than needed, free and fall through to MSI | * less vectors than needed. Free MSI-X resources | ||||
* and we'll try enabling MSI. | |||||
*/ | */ | ||||
pci_release_msi(dev); | pci_release_msi(dev); | ||||
msi: | msi: | ||||
if (adapter->msix_mem != NULL) { | if (adapter->msix_mem != NULL) { | ||||
bus_release_resource(dev, SYS_RES_MEMORY, | bus_release_resource(dev, SYS_RES_MEMORY, | ||||
rid, adapter->msix_mem); | rid, adapter->msix_mem); | ||||
adapter->msix_mem = NULL; | adapter->msix_mem = NULL; | ||||
} | } | ||||
msgs = 1; | msgs = 1; | ||||
if (pci_alloc_msi(dev, &msgs) == 0) { | if (pci_alloc_msi(dev, &msgs) == 0) { | ||||
device_printf(adapter->dev, "Using an MSI interrupt\n"); | device_printf(adapter->dev, "Using an MSI interrupt\n"); | ||||
return (msgs); | return (msgs); | ||||
} | } | ||||
device_printf(adapter->dev, "Using a Legacy interrupt\n"); | device_printf(adapter->dev, "Using a Legacy interrupt\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
/************************************************************************ | |||||
* ixgbe_allocate_pci_resources | |||||
************************************************************************/ | |||||
static int | static int | ||||
ixgbe_allocate_pci_resources(struct adapter *adapter) | ixgbe_allocate_pci_resources(struct adapter *adapter) | ||||
{ | { | ||||
int rid; | |||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
int rid; | |||||
rid = PCIR_BAR(0); | rid = PCIR_BAR(0); | ||||
adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | adapter->pci_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, | ||||
&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); | ||||
} | } | ||||
/* Save bus_space values for READ/WRITE_REG macros */ | /* Save bus_space values for READ/WRITE_REG macros */ | ||||
adapter->osdep.mem_bus_space_tag = | adapter->osdep.mem_bus_space_tag = rman_get_bustag(adapter->pci_mem); | ||||
rman_get_bustag(adapter->pci_mem); | |||||
adapter->osdep.mem_bus_space_handle = | adapter->osdep.mem_bus_space_handle = | ||||
rman_get_bushandle(adapter->pci_mem); | rman_get_bushandle(adapter->pci_mem); | ||||
/* Set hw values for shared code */ | /* Set hw values for shared code */ | ||||
adapter->hw.hw_addr = (u8 *) &adapter->osdep.mem_bus_space_handle; | adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; | ||||
adapter->hw.back = adapter; | adapter->hw.back = adapter; | ||||
/* Default to 1 queue if MSI-X setup fails */ | /* Default to 1 queue if MSI-X setup fails */ | ||||
adapter->num_queues = 1; | adapter->num_queues = 1; | ||||
/* | /* | ||||
** Now setup MSI or MSI-X, should | ** Now setup MSI or MSI-X, should | ||||
** return us the number of supported | ** return us the number of supported | ||||
** vectors. (Will be 1 for MSI) | ** vectors. (Will be 1 for MSI) | ||||
*/ | */ | ||||
adapter->msix = ixgbe_setup_msix(adapter); | adapter->msix = ixgbe_setup_msix(adapter); | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_allocate_pci_resources */ | ||||
/************************************************************************ | |||||
* ixgbe_free_pci_resources | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_free_pci_resources(struct adapter * adapter) | ixgbe_free_pci_resources(struct adapter *adapter) | ||||
{ | { | ||||
struct ix_queue *que = adapter->queues; | struct ix_queue *que = adapter->queues; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
int rid, memrid; | int rid, memrid; | ||||
if (adapter->hw.mac.type == ixgbe_mac_82598EB) | if (adapter->hw.mac.type == ixgbe_mac_82598EB) | ||||
memrid = PCIR_BAR(MSIX_82598_BAR); | memrid = PCIR_BAR(MSIX_82598_BAR); | ||||
else | else | ||||
memrid = PCIR_BAR(MSIX_82599_BAR); | memrid = PCIR_BAR(MSIX_82599_BAR); | ||||
/* | /* | ||||
** There is a slight possibility of a failure mode | * There is a slight possibility of a failure mode | ||||
** in attach that will result in entering this function | * in attach that will result in entering this function | ||||
** before interrupt resources have been initialized, and | * before interrupt resources have been initialized, and | ||||
** in that case we do not want to execute the loops below | * in that case we do not want to execute the loops below | ||||
** We can detect this reliably by the state of the adapter | * We can detect this reliably by the state of the adapter | ||||
** res pointer. | * res pointer. | ||||
*/ | */ | ||||
if (adapter->res == NULL) | if (adapter->res == NULL) | ||||
goto mem; | goto mem; | ||||
/* | /* | ||||
** Release all msix queue resources: | * Release all msix queue resources: | ||||
*/ | */ | ||||
for (int i = 0; i < adapter->num_queues; i++, que++) { | for (int i = 0; i < adapter->num_queues; i++, que++) { | ||||
rid = que->msix + 1; | rid = que->msix + 1; | ||||
if (que->tag != NULL) { | if (que->tag != NULL) { | ||||
bus_teardown_intr(dev, que->res, que->tag); | bus_teardown_intr(dev, que->res, que->tag); | ||||
que->tag = NULL; | que->tag = NULL; | ||||
} | } | ||||
if (que->res != NULL) | if (que->res != NULL) | ||||
bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); | bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); | ||||
} | } | ||||
/* Clean the Legacy or Link interrupt last */ | /* Clean the Legacy or Link interrupt last */ | ||||
if (adapter->vector) /* we are doing MSIX */ | if (adapter->vector) /* we are doing MSI-X */ | ||||
rid = adapter->vector + 1; | rid = adapter->vector + 1; | ||||
else | else | ||||
(adapter->msix != 0) ? (rid = 1):(rid = 0); | (adapter->msix != 0) ? (rid = 1):(rid = 0); | ||||
if (adapter->tag != NULL) { | if (adapter->tag != NULL) { | ||||
bus_teardown_intr(dev, adapter->res, adapter->tag); | bus_teardown_intr(dev, adapter->res, adapter->tag); | ||||
adapter->tag = NULL; | adapter->tag = NULL; | ||||
} | } | ||||
if (adapter->res != NULL) | if (adapter->res != NULL) | ||||
bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); | bus_release_resource(dev, SYS_RES_IRQ, rid, adapter->res); | ||||
mem: | mem: | ||||
if (adapter->msix) | if (adapter->msix) | ||||
pci_release_msi(dev); | pci_release_msi(dev); | ||||
if (adapter->msix_mem != NULL) | if (adapter->msix_mem != NULL) | ||||
bus_release_resource(dev, SYS_RES_MEMORY, | bus_release_resource(dev, SYS_RES_MEMORY, memrid, | ||||
memrid, adapter->msix_mem); | adapter->msix_mem); | ||||
if (adapter->pci_mem != NULL) | if (adapter->pci_mem != NULL) | ||||
bus_release_resource(dev, SYS_RES_MEMORY, | bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BAR(0), | ||||
PCIR_BAR(0), adapter->pci_mem); | adapter->pci_mem); | ||||
return; | return; | ||||
} | } /* ixgbe_free_pci_resources */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* ixgbe_setup_interface | |||||
* | * | ||||
* Setup networking device structure and register an interface. | * Setup networking device structure and register an interface. | ||||
* | ************************************************************************/ | ||||
**********************************************************************/ | |||||
static int | static int | ||||
ixgbe_setup_interface(device_t dev, struct adapter *adapter) | ixgbe_setup_interface(device_t dev, struct adapter *adapter) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
INIT_DEBUGOUT("ixgbe_setup_interface: begin"); | INIT_DEBUGOUT("ixgbe_setup_interface: begin"); | ||||
ifp = adapter->ifp = if_alloc(IFT_ETHER); | ifp = adapter->ifp = if_alloc(IFT_ETHER); | ||||
if (ifp == NULL) { | if (ifp == NULL) { | ||||
device_printf(dev, "can not allocate ifnet structure\n"); | device_printf(dev, "can not allocate ifnet structure\n"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
Show All 19 Lines | #else | ||||
ifp->if_start = ixgbe_start; | ifp->if_start = ixgbe_start; | ||||
IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); | IFQ_SET_MAXLEN(&ifp->if_snd, adapter->num_tx_desc - 2); | ||||
ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; | ifp->if_snd.ifq_drv_maxlen = adapter->num_tx_desc - 2; | ||||
IFQ_SET_READY(&ifp->if_snd); | IFQ_SET_READY(&ifp->if_snd); | ||||
#endif | #endif | ||||
ether_ifattach(ifp, adapter->hw.mac.addr); | ether_ifattach(ifp, adapter->hw.mac.addr); | ||||
adapter->max_frame_size = | adapter->max_frame_size = ifp->if_mtu + IXGBE_MTU_HDR; | ||||
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; | |||||
/* | /* | ||||
* Tell the upper layer(s) we support long frames. | * Tell the upper layer(s) we support long frames. | ||||
*/ | */ | ||||
ifp->if_hdrlen = sizeof(struct ether_vlan_header); | ifp->if_hdrlen = sizeof(struct ether_vlan_header); | ||||
/* Set capability flags */ | /* Set capability flags */ | ||||
ifp->if_capabilities |= IFCAP_RXCSUM | ifp->if_capabilities |= IFCAP_RXCSUM | ||||
| IFCAP_TXCSUM | | IFCAP_TXCSUM | ||||
| IFCAP_RXCSUM_IPV6 | | IFCAP_RXCSUM_IPV6 | ||||
| IFCAP_TXCSUM_IPV6 | | IFCAP_TXCSUM_IPV6 | ||||
| IFCAP_TSO4 | | IFCAP_TSO4 | ||||
| IFCAP_TSO6 | | IFCAP_TSO6 | ||||
| IFCAP_LRO | | IFCAP_LRO | ||||
| IFCAP_VLAN_HWTAGGING | | IFCAP_VLAN_HWTAGGING | ||||
| IFCAP_VLAN_HWTSO | | IFCAP_VLAN_HWTSO | ||||
| IFCAP_VLAN_HWCSUM | | IFCAP_VLAN_HWCSUM | ||||
| IFCAP_JUMBO_MTU | | IFCAP_JUMBO_MTU | ||||
| IFCAP_VLAN_MTU | | IFCAP_VLAN_MTU | ||||
| IFCAP_HWSTATS; | | IFCAP_HWSTATS; | ||||
/* Enable the above capabilities by default */ | /* Enable the above capabilities by default */ | ||||
ifp->if_capenable = ifp->if_capabilities; | ifp->if_capenable = ifp->if_capabilities; | ||||
/* | /* | ||||
** Don't turn this on by default, if vlans are | * Don't turn this on by default, if vlans are | ||||
** created on another pseudo device (eg. lagg) | * created on another pseudo device (eg. lagg) | ||||
** then vlan events are not passed thru, breaking | * then vlan events are not passed thru, breaking | ||||
** operation, but with HW FILTER off it works. If | * operation, but with HW FILTER off it works. If | ||||
** using vlans directly on the ixgbe driver you can | * using vlans directly on the ixgbe driver you can | ||||
** enable this and get full hardware tag filtering. | * enable this and get full hardware tag filtering. | ||||
*/ | */ | ||||
ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; | ifp->if_capabilities |= IFCAP_VLAN_HWFILTER; | ||||
/* | /* | ||||
* Specify the media types supported by this adapter and register | * Specify the media types supported by this adapter and register | ||||
* callbacks to update media and link information | * callbacks to update media and link information | ||||
*/ | */ | ||||
ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, | ifmedia_init(&adapter->media, IFM_IMASK, ixgbe_media_change, | ||||
ixgbe_media_status); | ixgbe_media_status); | ||||
adapter->phy_layer = ixgbe_get_supported_physical_layer(&adapter->hw); | adapter->phy_layer = ixgbe_get_supported_physical_layer(&adapter->hw); | ||||
ixgbe_add_media_types(adapter); | ixgbe_add_media_types(adapter); | ||||
/* Set autoselect media by default */ | /* Set autoselect media by default */ | ||||
ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); | ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_setup_interface */ | ||||
/************************************************************************ | |||||
* ixgbe_add_media_types | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_add_media_types(struct adapter *adapter) | ixgbe_add_media_types(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
int layer; | int layer; | ||||
layer = adapter->phy_layer; | layer = adapter->phy_layer; | ||||
/* Media types with matching FreeBSD media defines */ | /* Media types with matching FreeBSD media defines */ | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_T) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_T, 0, NULL); | ||||
if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) | if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_T) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); | ||||
if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) | if (layer & IXGBE_PHYSICAL_LAYER_100BASE_TX) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_100_TX, 0, NULL); | ||||
if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || | if (layer & IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU || | ||||
layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) | layer & IXGBE_PHYSICAL_LAYER_SFP_ACTIVE_DA) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_TWINAX, 0, | ||||
NULL); | |||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) { | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_LR) { | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); | ||||
if (hw->phy.multispeed_fiber) | if (hw->phy.multispeed_fiber) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, | ||||
NULL); | |||||
} | } | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_SR) { | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_SR, 0, NULL); | ||||
if (hw->phy.multispeed_fiber) | if (hw->phy.multispeed_fiber) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, | ||||
NULL); | |||||
} else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) | } else if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_SX) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_SX, 0, NULL); | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_CX4) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_CX4, 0, NULL); | ||||
#ifdef IFM_ETH_XTYPE | #ifdef IFM_ETH_XTYPE | ||||
if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) | if (layer & IXGBE_PHYSICAL_LAYER_10GBASE_KR) | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KR, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_KR, 0, NULL); | ||||
Show All 15 Lines | #else | ||||
if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) { | if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_KX) { | ||||
device_printf(dev, "Media supported: 1000baseKX\n"); | device_printf(dev, "Media supported: 1000baseKX\n"); | ||||
device_printf(dev, "1000baseKX mapped to 1000baseCX\n"); | device_printf(dev, "1000baseKX mapped to 1000baseCX\n"); | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_CX, 0, NULL); | ||||
} | } | ||||
#endif | #endif | ||||
if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) | if (layer & IXGBE_PHYSICAL_LAYER_1000BASE_BX) | ||||
device_printf(dev, "Media supported: 1000baseBX\n"); | device_printf(dev, "Media supported: 1000baseBX\n"); | ||||
if (hw->device_id == IXGBE_DEV_ID_82598AT) { | if (hw->device_id == IXGBE_DEV_ID_82598AT) { | ||||
ifmedia_add(&adapter->media, | ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T | IFM_FDX, | ||||
IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); | 0, NULL); | ||||
ifmedia_add(&adapter->media, | ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_T, 0, NULL); | ||||
IFM_ETHER | IFM_1000_T, 0, NULL); | |||||
} | } | ||||
ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); | ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); | ||||
} | } /* ixgbe_add_media_types */ | ||||
/************************************************************************ | |||||
* ixgbe_config_link | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_config_link(struct adapter *adapter) | ixgbe_config_link(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 autoneg, err = 0; | u32 autoneg, err = 0; | ||||
bool sfp, negotiate; | bool sfp, negotiate; | ||||
sfp = ixgbe_is_sfp(hw); | sfp = ixgbe_is_sfp(hw); | ||||
if (sfp) { | if (sfp) { | ||||
taskqueue_enqueue(adapter->tq, &adapter->mod_task); | taskqueue_enqueue(adapter->tq, &adapter->mod_task); | ||||
} else { | } else { | ||||
if (hw->mac.ops.check_link) | if (hw->mac.ops.check_link) | ||||
err = ixgbe_check_link(hw, &adapter->link_speed, | err = ixgbe_check_link(hw, &adapter->link_speed, | ||||
&adapter->link_up, FALSE); | &adapter->link_up, FALSE); | ||||
if (err) | if (err) | ||||
goto out; | goto out; | ||||
autoneg = hw->phy.autoneg_advertised; | autoneg = hw->phy.autoneg_advertised; | ||||
if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) | if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) | ||||
err = hw->mac.ops.get_link_capabilities(hw, | err = hw->mac.ops.get_link_capabilities(hw, &autoneg, | ||||
&autoneg, &negotiate); | &negotiate); | ||||
if (err) | if (err) | ||||
goto out; | goto out; | ||||
if (hw->mac.ops.setup_link) | if (hw->mac.ops.setup_link) | ||||
err = hw->mac.ops.setup_link(hw, | err = hw->mac.ops.setup_link(hw, autoneg, | ||||
autoneg, adapter->link_up); | adapter->link_up); | ||||
} | } | ||||
out: | out: | ||||
return; | return; | ||||
} | } /* ixgbe_config_link */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * ixgbe_initialize_transmit_units - Enable transmit units. | ||||
* Enable transmit units. | ************************************************************************/ | ||||
* | |||||
**********************************************************************/ | |||||
static void | static void | ||||
ixgbe_initialize_transmit_units(struct adapter *adapter) | ixgbe_initialize_transmit_units(struct adapter *adapter) | ||||
{ | { | ||||
struct tx_ring *txr = adapter->tx_rings; | struct tx_ring *txr = adapter->tx_rings; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
/* Setup the Base and Length of the Tx Descriptor Ring */ | /* Setup the Base and Length of the Tx Descriptor Ring */ | ||||
for (int i = 0; i < adapter->num_queues; i++, txr++) { | for (int i = 0; i < adapter->num_queues; i++, txr++) { | ||||
u64 tdba = txr->txdma.dma_paddr; | u64 tdba = txr->txdma.dma_paddr; | ||||
u32 txctrl = 0; | u32 txctrl = 0; | ||||
int j = txr->me; | int j = txr->me; | ||||
IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), | IXGBE_WRITE_REG(hw, IXGBE_TDBAL(j), | ||||
(tdba & 0x00000000ffffffffULL)); | (tdba & 0x00000000ffffffffULL)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); | IXGBE_WRITE_REG(hw, IXGBE_TDBAH(j), (tdba >> 32)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), | IXGBE_WRITE_REG(hw, IXGBE_TDLEN(j), | ||||
adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); | adapter->num_tx_desc * sizeof(union ixgbe_adv_tx_desc)); | ||||
/* Setup the HW Tx Head and Tail descriptor pointers */ | /* Setup the HW Tx Head and Tail descriptor pointers */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); | IXGBE_WRITE_REG(hw, IXGBE_TDH(j), 0); | ||||
IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); | IXGBE_WRITE_REG(hw, IXGBE_TDT(j), 0); | ||||
/* Cache the tail address */ | /* Cache the tail address */ | ||||
txr->tail = IXGBE_TDT(j); | txr->tail = IXGBE_TDT(j); | ||||
/* Disable Head Writeback */ | /* Disable Head Writeback */ | ||||
/* | /* | ||||
* Note: for X550 series devices, these registers are actually | * Note: for X550 series devices, these registers are actually | ||||
* prefixed with TPH_ isntead of DCA_, but the addresses and | * prefixed with TPH_ isntead of DCA_, but the addresses and | ||||
* fields remain the same. | * fields remain the same. | ||||
*/ | */ | ||||
switch (hw->mac.type) { | switch (hw->mac.type) { | ||||
case ixgbe_mac_82598EB: | case ixgbe_mac_82598EB: | ||||
txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); | txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(j)); | ||||
break; | break; | ||||
default: | default: | ||||
txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j)); | txctrl = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(j)); | ||||
break; | break; | ||||
} | } | ||||
txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; | txctrl &= ~IXGBE_DCA_TXCTRL_DESC_WRO_EN; | ||||
switch (hw->mac.type) { | switch (hw->mac.type) { | ||||
case ixgbe_mac_82598EB: | case ixgbe_mac_82598EB: | ||||
IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); | IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl); | ||||
break; | break; | ||||
default: | default: | ||||
IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl); | IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(j), txctrl); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (hw->mac.type != ixgbe_mac_82598EB) { | if (hw->mac.type != ixgbe_mac_82598EB) { | ||||
u32 dmatxctl, rttdcs; | u32 dmatxctl, rttdcs; | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
enum ixgbe_iov_mode mode = ixgbe_get_iov_mode(adapter); | enum ixgbe_iov_mode mode = ixgbe_get_iov_mode(adapter); | ||||
#endif | #endif | ||||
dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); | dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); | ||||
dmatxctl |= IXGBE_DMATXCTL_TE; | dmatxctl |= IXGBE_DMATXCTL_TE; | ||||
IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); | IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl); | ||||
/* Disable arbiter to set MTQC */ | /* Disable arbiter to set MTQC */ | ||||
rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); | rttdcs = IXGBE_READ_REG(hw, IXGBE_RTTDCS); | ||||
rttdcs |= IXGBE_RTTDCS_ARBDIS; | rttdcs |= IXGBE_RTTDCS_ARBDIS; | ||||
IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); | IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
IXGBE_WRITE_REG(hw, IXGBE_MTQC, ixgbe_get_mtqc(mode)); | IXGBE_WRITE_REG(hw, IXGBE_MTQC, ixgbe_get_mtqc(mode)); | ||||
#else | #else | ||||
IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); | IXGBE_WRITE_REG(hw, IXGBE_MTQC, IXGBE_MTQC_64Q_1PB); | ||||
#endif | #endif | ||||
rttdcs &= ~IXGBE_RTTDCS_ARBDIS; | rttdcs &= ~IXGBE_RTTDCS_ARBDIS; | ||||
IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); | IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, rttdcs); | ||||
} | } | ||||
return; | return; | ||||
} | } /* ixgbe_initialize_transmit_units */ | ||||
/************************************************************************ | |||||
* ixgbe_initialize_rss_mapping | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_initialize_rss_mapping(struct adapter *adapter) | ixgbe_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]; | ||||
int queue_id, table_size, index_mult; | int queue_id, table_size, index_mult; | ||||
int i, j; | |||||
#ifdef RSS | #ifdef RSS | ||||
u32 rss_hash_config; | u32 rss_hash_config; | ||||
#endif | #endif | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
enum ixgbe_iov_mode mode; | enum ixgbe_iov_mode mode; | ||||
#endif | #endif | ||||
#ifdef RSS | #ifdef RSS | ||||
/* Fetch the configured RSS key */ | /* Fetch the configured RSS key */ | ||||
rss_getkey((uint8_t *) &rss_key); | rss_getkey((uint8_t *)&rss_key); | ||||
#else | #else | ||||
/* set up random bits */ | /* set up random bits */ | ||||
arc4rand(&rss_key, sizeof(rss_key), 0); | arc4rand(&rss_key, sizeof(rss_key), 0); | ||||
#endif | #endif | ||||
/* Set multiplier for RETA setup and table size based on MAC */ | /* Set multiplier for RETA setup and table size based on MAC */ | ||||
index_mult = 0x1; | index_mult = 0x1; | ||||
table_size = 128; | table_size = 128; | ||||
switch (adapter->hw.mac.type) { | switch (adapter->hw.mac.type) { | ||||
case ixgbe_mac_82598EB: | case ixgbe_mac_82598EB: | ||||
index_mult = 0x11; | index_mult = 0x11; | ||||
break; | break; | ||||
case ixgbe_mac_X550: | case ixgbe_mac_X550: | ||||
case ixgbe_mac_X550EM_x: | case ixgbe_mac_X550EM_x: | ||||
table_size = 512; | table_size = 512; | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
/* Set up the redirection table */ | /* Set up the redirection table */ | ||||
for (int i = 0, j = 0; i < table_size; i++, j++) { | for (i = 0, j = 0; i < table_size; i++, j++) { | ||||
if (j == adapter->num_queues) j = 0; | if (j == adapter->num_queues) j = 0; | ||||
#ifdef RSS | #ifdef RSS | ||||
/* | /* | ||||
* Fetch the RSS bucket id for the given indirection entry. | * Fetch the RSS bucket id for the given indirection entry. | ||||
* Cap it at the number of configured buckets (which is | * Cap it at the number of configured buckets (which is | ||||
* num_queues.) | * num_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_queues; | ||||
#else | #else | ||||
queue_id = (j * index_mult); | queue_id = (j * index_mult); | ||||
#endif | #endif | ||||
/* | /* | ||||
* 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 = reta >> 8; | reta = reta >> 8; | ||||
reta = reta | ( ((uint32_t) queue_id) << 24); | reta = reta | (((uint32_t)queue_id) << 24); | ||||
if ((i & 3) == 3) { | if ((i & 3) == 3) { | ||||
if (i < 128) | if (i < 128) | ||||
IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); | IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), reta); | ||||
else | else | ||||
IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), reta); | IXGBE_WRITE_REG(hw, IXGBE_ERETA((i >> 2) - 32), | ||||
reta); | |||||
reta = 0; | reta = 0; | ||||
} | } | ||||
} | } | ||||
/* Now fill our hash function seeds */ | /* Now fill our hash function seeds */ | ||||
for (int i = 0; i < 10; i++) | for (i = 0; i < 10; i++) | ||||
IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); | IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), rss_key[i]); | ||||
/* Perform hash on these packet types */ | /* Perform hash on these packet types */ | ||||
#ifdef RSS | #ifdef RSS | ||||
mrqc = IXGBE_MRQC_RSSEN; | mrqc = IXGBE_MRQC_RSSEN; | ||||
rss_hash_config = rss_gethashconfig(); | rss_hash_config = rss_gethashconfig(); | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) | if (rss_hash_config & RSS_HASHTYPE_RSS_IPV4) | ||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; | mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4; | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) | if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV4) | ||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; | mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_TCP; | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) | if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) | ||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; | mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6; | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) | if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) | ||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; | mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_TCP; | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) | if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) | ||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; | mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX; | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) | if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6_EX) | ||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; | mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP; | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) | if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4) | ||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; | mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) | if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV4_EX) | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, "%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, but not supported\n", | ||||
"%s: RSS_HASHTYPE_RSS_UDP_IPV4_EX defined, " | __func__); | ||||
"but not supported\n", __func__); | |||||
if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) | if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) | ||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; | mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) | if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6_EX) | ||||
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; | mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP; | ||||
#else | #else | ||||
/* | /* | ||||
* Disable UDP - IP fragments aren't currently being handled | * Disable UDP - IP fragments aren't currently being handled | ||||
* and so we end up with a mix of 2-tuple and 4-tuple | * and so we end up with a mix of 2-tuple and 4-tuple | ||||
* traffic. | * traffic. | ||||
*/ | */ | ||||
mrqc = IXGBE_MRQC_RSSEN | mrqc = IXGBE_MRQC_RSSEN | ||||
| IXGBE_MRQC_RSS_FIELD_IPV4 | | IXGBE_MRQC_RSS_FIELD_IPV4 | ||||
| IXGBE_MRQC_RSS_FIELD_IPV4_TCP | | IXGBE_MRQC_RSS_FIELD_IPV4_TCP | ||||
| IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP | ||||
| IXGBE_MRQC_RSS_FIELD_IPV6_EX | | IXGBE_MRQC_RSS_FIELD_IPV6_EX | ||||
| IXGBE_MRQC_RSS_FIELD_IPV6 | | IXGBE_MRQC_RSS_FIELD_IPV6 | ||||
| IXGBE_MRQC_RSS_FIELD_IPV6_TCP | | IXGBE_MRQC_RSS_FIELD_IPV6_TCP | ||||
; | ; | ||||
#endif /* RSS */ | #endif /* RSS */ | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
mode = ixgbe_get_iov_mode(adapter); | mode = ixgbe_get_iov_mode(adapter); | ||||
mrqc |= ixgbe_get_mrqc(mode); | mrqc |= ixgbe_get_mrqc(mode); | ||||
#endif | #endif | ||||
IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); | IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); | ||||
} | } /* ixgbe_initialize_rss_mapping */ | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * ixgbe_initialize_receive_units - Setup receive registers and features. | ||||
* Setup receive registers and features. | ************************************************************************/ | ||||
* | |||||
**********************************************************************/ | |||||
#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 | #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 | ||||
#define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1) | #define BSIZEPKT_ROUNDUP ((1<<IXGBE_SRRCTL_BSIZEPKT_SHIFT)-1) | ||||
static void | static void | ||||
ixgbe_initialize_receive_units(struct adapter *adapter) | ixgbe_initialize_receive_units(struct adapter *adapter) | ||||
{ | { | ||||
struct rx_ring *rxr = adapter->rx_rings; | struct rx_ring *rxr = adapter->rx_rings; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
int i, j; | |||||
u32 bufsz, fctrl, srrctl, rxcsum; | u32 bufsz, fctrl, srrctl, rxcsum; | ||||
u32 hlreg; | u32 hlreg; | ||||
/* | /* | ||||
* Make sure receives are disabled while | * Make sure receives are disabled while | ||||
* setting up the descriptor ring | * setting up the descriptor ring | ||||
*/ | */ | ||||
ixgbe_disable_rx(hw); | ixgbe_disable_rx(hw); | ||||
/* Enable broadcasts */ | /* Enable broadcasts */ | ||||
fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); | fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); | ||||
fctrl |= IXGBE_FCTRL_BAM; | fctrl |= IXGBE_FCTRL_BAM; | ||||
if (adapter->hw.mac.type == ixgbe_mac_82598EB) { | if (adapter->hw.mac.type == ixgbe_mac_82598EB) { | ||||
fctrl |= IXGBE_FCTRL_DPF; | fctrl |= IXGBE_FCTRL_DPF; | ||||
fctrl |= IXGBE_FCTRL_PMCF; | fctrl |= IXGBE_FCTRL_PMCF; | ||||
} | } | ||||
IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); | IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); | ||||
/* Set for Jumbo Frames? */ | /* Set for Jumbo Frames? */ | ||||
hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); | hlreg = IXGBE_READ_REG(hw, IXGBE_HLREG0); | ||||
if (ifp->if_mtu > ETHERMTU) | if (ifp->if_mtu > ETHERMTU) | ||||
hlreg |= IXGBE_HLREG0_JUMBOEN; | hlreg |= IXGBE_HLREG0_JUMBOEN; | ||||
else | else | ||||
hlreg &= ~IXGBE_HLREG0_JUMBOEN; | hlreg &= ~IXGBE_HLREG0_JUMBOEN; | ||||
#ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
/* crcstrip is conditional in netmap (in RDRXCTL too ?) */ | /* crcstrip is conditional in netmap (in RDRXCTL too ?) */ | ||||
if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) | if (ifp->if_capenable & IFCAP_NETMAP && !ix_crcstrip) | ||||
hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; | hlreg &= ~IXGBE_HLREG0_RXCRCSTRP; | ||||
else | else | ||||
hlreg |= IXGBE_HLREG0_RXCRCSTRP; | hlreg |= IXGBE_HLREG0_RXCRCSTRP; | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); | IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg); | ||||
bufsz = (adapter->rx_mbuf_sz + | bufsz = (adapter->rx_mbuf_sz + BSIZEPKT_ROUNDUP) >> | ||||
BSIZEPKT_ROUNDUP) >> IXGBE_SRRCTL_BSIZEPKT_SHIFT; | IXGBE_SRRCTL_BSIZEPKT_SHIFT; | ||||
for (int i = 0; i < adapter->num_queues; i++, rxr++) { | for (i = 0; i < adapter->num_queues; i++, rxr++) { | ||||
u64 rdba = rxr->rxdma.dma_paddr; | u64 rdba = rxr->rxdma.dma_paddr; | ||||
int j = rxr->me; | j = rxr->me; | ||||
/* 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_RDBAL(j), | IXGBE_WRITE_REG(hw, IXGBE_RDBAL(j), | ||||
(rdba & 0x00000000ffffffffULL)); | (rdba & 0x00000000ffffffffULL)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); | IXGBE_WRITE_REG(hw, IXGBE_RDBAH(j), (rdba >> 32)); | ||||
IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), | IXGBE_WRITE_REG(hw, IXGBE_RDLEN(j), | ||||
adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); | adapter->num_rx_desc * sizeof(union ixgbe_adv_rx_desc)); | ||||
/* Set up the SRRCTL register */ | /* Set up the SRRCTL register */ | ||||
srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j)); | srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(j)); | ||||
srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; | srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK; | ||||
srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; | srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK; | ||||
Show All 19 Lines | for (i = 0; i < adapter->num_queues; i++, rxr++) { | ||||
IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0); | IXGBE_WRITE_REG(hw, IXGBE_RDH(j), 0); | ||||
IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0); | IXGBE_WRITE_REG(hw, IXGBE_RDT(j), 0); | ||||
/* Set the driver rx tail address */ | /* Set the driver rx tail address */ | ||||
rxr->tail = IXGBE_RDT(rxr->me); | rxr->tail = IXGBE_RDT(rxr->me); | ||||
} | } | ||||
if (adapter->hw.mac.type != ixgbe_mac_82598EB) { | if (adapter->hw.mac.type != ixgbe_mac_82598EB) { | ||||
u32 psrtype = IXGBE_PSRTYPE_TCPHDR | | u32 psrtype = IXGBE_PSRTYPE_TCPHDR | ||||
IXGBE_PSRTYPE_UDPHDR | | | IXGBE_PSRTYPE_UDPHDR | ||||
IXGBE_PSRTYPE_IPV4HDR | | | IXGBE_PSRTYPE_IPV4HDR | ||||
IXGBE_PSRTYPE_IPV6HDR; | | IXGBE_PSRTYPE_IPV6HDR; | ||||
IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); | IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype); | ||||
} | } | ||||
rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); | rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM); | ||||
ixgbe_initialize_rss_mapping(adapter); | ixgbe_initialize_rss_mapping(adapter); | ||||
if (adapter->num_queues > 1) { | if (adapter->num_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; | ||||
/* This is useful for calculating UDP/IP fragment checksums */ | /* This is useful for calculating UDP/IP fragment checksums */ | ||||
if (!(rxcsum & IXGBE_RXCSUM_PCSD)) | if (!(rxcsum & IXGBE_RXCSUM_PCSD)) | ||||
rxcsum |= IXGBE_RXCSUM_IPPCSE; | rxcsum |= IXGBE_RXCSUM_IPPCSE; | ||||
IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); | IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum); | ||||
return; | return; | ||||
} | } /* ixgbe_initialize_receive_units */ | ||||
/* | /************************************************************************ | ||||
** This routine is run via an vlan config EVENT, | * ixgbe_register_vlan | ||||
** it enables us to use the HW Filter table since | * | ||||
** we can get the vlan id. This just creates the | * Run via vlan config EVENT, it enables us to use the | ||||
** entry in the soft version of the VFTA, init will | * HW Filter table since we can get the vlan id. This | ||||
** repopulate the real table. | * just creates the entry in the soft version of the | ||||
*/ | * VFTA, init will repopulate the real table. | ||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) | ixgbe_register_vlan(void *arg, struct ifnet *ifp, u16 vtag) | ||||
{ | { | ||||
struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = ifp->if_softc; | ||||
u16 index, bit; | u16 index, bit; | ||||
if (ifp->if_softc != arg) /* Not our event */ | if (ifp->if_softc != arg) /* Not our event */ | ||||
return; | return; | ||||
if ((vtag == 0) || (vtag > 4095)) /* Invalid */ | if ((vtag == 0) || (vtag > 4095)) /* Invalid */ | ||||
return; | return; | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
index = (vtag >> 5) & 0x7F; | index = (vtag >> 5) & 0x7F; | ||||
bit = vtag & 0x1F; | bit = vtag & 0x1F; | ||||
adapter->shadow_vfta[index] |= (1 << bit); | adapter->shadow_vfta[index] |= (1 << bit); | ||||
++adapter->num_vlans; | ++adapter->num_vlans; | ||||
ixgbe_setup_vlan_hw_support(adapter); | ixgbe_setup_vlan_hw_support(adapter); | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
} | } /* ixgbe_register_vlan */ | ||||
/* | /************************************************************************ | ||||
** This routine is run via an vlan | * ixgbe_unregister_vlan | ||||
** unconfig EVENT, remove our entry | * | ||||
** in the soft vfta. | * Run via vlan unconfig EVENT, remove our entry in the soft vfta. | ||||
*/ | ************************************************************************/ | ||||
static void | static void | ||||
ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) | ixgbe_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) | ||||
{ | { | ||||
struct adapter *adapter = ifp->if_softc; | struct adapter *adapter = ifp->if_softc; | ||||
u16 index, bit; | u16 index, bit; | ||||
if (ifp->if_softc != arg) | if (ifp->if_softc != arg) | ||||
return; | return; | ||||
if ((vtag == 0) || (vtag > 4095)) /* Invalid */ | if ((vtag == 0) || (vtag > 4095)) /* Invalid */ | ||||
return; | return; | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
index = (vtag >> 5) & 0x7F; | index = (vtag >> 5) & 0x7F; | ||||
bit = vtag & 0x1F; | bit = vtag & 0x1F; | ||||
adapter->shadow_vfta[index] &= ~(1 << bit); | adapter->shadow_vfta[index] &= ~(1 << bit); | ||||
--adapter->num_vlans; | --adapter->num_vlans; | ||||
/* Re-init to load the changes */ | /* Re-init to load the changes */ | ||||
ixgbe_setup_vlan_hw_support(adapter); | ixgbe_setup_vlan_hw_support(adapter); | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
} | } /* ixgbe_unregister_vlan */ | ||||
/************************************************************************ | |||||
* ixgbe_setup_vlan_hw_support | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_setup_vlan_hw_support(struct adapter *adapter) | ixgbe_setup_vlan_hw_support(struct adapter *adapter) | ||||
{ | { | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
struct rx_ring *rxr; | struct rx_ring *rxr; | ||||
int i; | |||||
u32 ctrl; | u32 ctrl; | ||||
/* | /* | ||||
** We get here thru init_locked, meaning | * We get here thru init_locked, meaning | ||||
** a soft reset, this has already cleared | * a soft reset, this has already cleared | ||||
** the VFTA and other state, so if there | * the VFTA and other state, so if there | ||||
** have been no vlan's registered do nothing. | * have been no vlan's registered do nothing. | ||||
*/ | */ | ||||
if (adapter->num_vlans == 0) | if (adapter->num_vlans == 0) | ||||
return; | return; | ||||
/* Setup the queues for vlans */ | /* Setup the queues for vlans */ | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (i = 0; i < adapter->num_queues; i++) { | ||||
rxr = &adapter->rx_rings[i]; | rxr = &adapter->rx_rings[i]; | ||||
/* On 82599 the VLAN enable is per/queue in RXDCTL */ | /* On 82599 the VLAN enable is per/queue in RXDCTL */ | ||||
if (hw->mac.type != ixgbe_mac_82598EB) { | if (hw->mac.type != ixgbe_mac_82598EB) { | ||||
ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); | ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxr->me)); | ||||
ctrl |= IXGBE_RXDCTL_VME; | ctrl |= IXGBE_RXDCTL_VME; | ||||
IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl); | IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxr->me), ctrl); | ||||
} | } | ||||
rxr->vtag_strip = TRUE; | rxr->vtag_strip = TRUE; | ||||
} | } | ||||
if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) | if ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0) | ||||
return; | return; | ||||
/* | /* | ||||
** 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 (i = 0; i < IXGBE_VFTA_SIZE; i++) | ||||
if (adapter->shadow_vfta[i] != 0) | if (adapter->shadow_vfta[i] != 0) | ||||
IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), | IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), | ||||
adapter->shadow_vfta[i]); | adapter->shadow_vfta[i]); | ||||
ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); | ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); | ||||
/* Enable the Filter Table if enabled */ | /* Enable the Filter Table if enabled */ | ||||
if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { | if (ifp->if_capenable & IFCAP_VLAN_HWFILTER) { | ||||
ctrl &= ~IXGBE_VLNCTRL_CFIEN; | ctrl &= ~IXGBE_VLNCTRL_CFIEN; | ||||
ctrl |= IXGBE_VLNCTRL_VFE; | ctrl |= IXGBE_VLNCTRL_VFE; | ||||
} | } | ||||
if (hw->mac.type == ixgbe_mac_82598EB) | if (hw->mac.type == ixgbe_mac_82598EB) | ||||
ctrl |= IXGBE_VLNCTRL_VME; | ctrl |= IXGBE_VLNCTRL_VME; | ||||
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); | IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); | ||||
} | } /* ixgbe_setup_vlan_hw_support */ | ||||
static void | static void | ||||
ixgbe_enable_intr(struct adapter *adapter) | ixgbe_enable_intr(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
struct ix_queue *que = adapter->queues; | struct ix_queue *que = adapter->queues; | ||||
u32 mask, fwsm; | u32 mask, fwsm; | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (adapter->msix_mem) { | ||||
mask &= ~IXGBE_EIMS_LSC; | mask &= ~IXGBE_EIMS_LSC; | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
mask &= ~IXGBE_EIMS_MAILBOX; | mask &= ~IXGBE_EIMS_MAILBOX; | ||||
#endif | #endif | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); | IXGBE_WRITE_REG(hw, IXGBE_EIAC, mask); | ||||
} | } | ||||
/* | /* | ||||
** Now enable all queues, this is done separately to | * Now enable all queues, this is done separately to | ||||
** allow for handling the extended (beyond 32) MSIX | * allow for handling the extended (beyond 32) MSI-X | ||||
** vectors that can be used by 82599 | * vectors that can be used by 82599 | ||||
*/ | */ | ||||
for (int i = 0; i < adapter->num_queues; i++, que++) | for (int i = 0; i < adapter->num_queues; i++, que++) | ||||
ixgbe_enable_queue(adapter, que->msix); | ixgbe_enable_queue(adapter, que->msix); | ||||
IXGBE_WRITE_FLUSH(hw); | IXGBE_WRITE_FLUSH(hw); | ||||
return; | return; | ||||
} | } | ||||
Show All 34 Lines | if (hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) { | ||||
case ixgbe_mac_X550EM_x: | case ixgbe_mac_X550EM_x: | ||||
return; | return; | ||||
default: | default: | ||||
goto display; | goto display; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
** For the Quad port adapter we need to parse back | * For the Quad port adapter we need to parse back | ||||
** up the PCI tree to find the speed of the expansion | * up the PCI tree to find the speed of the expansion | ||||
** slot into which this adapter is plugged. A bit more work. | * slot into which this adapter is plugged. A bit more work. | ||||
*/ | */ | ||||
dev = device_get_parent(device_get_parent(dev)); | dev = device_get_parent(device_get_parent(dev)); | ||||
#ifdef IXGBE_DEBUG | #ifdef IXGBE_DEBUG | ||||
device_printf(dev, "parent pcib = %x,%x,%x\n", | device_printf(dev, "parent pcib = %x,%x,%x\n", pci_get_bus(dev), | ||||
pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); | pci_get_slot(dev), pci_get_function(dev)); | ||||
#endif | #endif | ||||
dev = device_get_parent(device_get_parent(dev)); | dev = device_get_parent(device_get_parent(dev)); | ||||
#ifdef IXGBE_DEBUG | #ifdef IXGBE_DEBUG | ||||
device_printf(dev, "slot pcib = %x,%x,%x\n", | device_printf(dev, "slot pcib = %x,%x,%x\n", pci_get_bus(dev), | ||||
pci_get_bus(dev), pci_get_slot(dev), pci_get_function(dev)); | pci_get_slot(dev), pci_get_function(dev)); | ||||
#endif | #endif | ||||
/* Now get the PCI Express Capabilities offset */ | /* Now get the PCI Express Capabilities offset */ | ||||
pci_find_cap(dev, PCIY_EXPRESS, &offset); | pci_find_cap(dev, PCIY_EXPRESS, &offset); | ||||
/* ...and read the Link Status Register */ | /* ...and read the Link Status Register */ | ||||
link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); | link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); | ||||
switch (link & IXGBE_PCI_LINK_WIDTH) { | switch (link & IXGBE_PCI_LINK_WIDTH) { | ||||
case IXGBE_PCI_LINK_WIDTH_1: | case IXGBE_PCI_LINK_WIDTH_1: | ||||
hw->bus.width = ixgbe_bus_width_pcie_x1; | hw->bus.width = ixgbe_bus_width_pcie_x1; | ||||
Show All 25 Lines | #endif | ||||
default: | default: | ||||
hw->bus.speed = ixgbe_bus_speed_unknown; | hw->bus.speed = ixgbe_bus_speed_unknown; | ||||
break; | break; | ||||
} | } | ||||
mac->ops.set_lan_id(hw); | mac->ops.set_lan_id(hw); | ||||
display: | display: | ||||
device_printf(dev,"PCI Express Bus: Speed %s %s\n", | device_printf(dev, "PCI Express Bus: Speed %s %s\n", | ||||
((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s": | ((hw->bus.speed == ixgbe_bus_speed_8000) ? "8.0GT/s" : | ||||
(hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s": | (hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0GT/s" : | ||||
(hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s":"Unknown"), | (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5GT/s" : | ||||
(hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : | "Unknown"), | ||||
((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" : | |||||
(hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : | (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" : | ||||
(hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : | (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" : | ||||
("Unknown")); | "Unknown")); | ||||
if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) && | if ((hw->device_id != IXGBE_DEV_ID_82599_SFP_SF_QP) && | ||||
((hw->bus.width <= ixgbe_bus_width_pcie_x4) && | ((hw->bus.width <= ixgbe_bus_width_pcie_x4) && | ||||
(hw->bus.speed == ixgbe_bus_speed_2500))) { | (hw->bus.speed == ixgbe_bus_speed_2500))) { | ||||
device_printf(dev, "PCI-Express bandwidth available" | device_printf(dev, "PCI-Express bandwidth available for this card\n is not sufficient for optimal performance.\n"); | ||||
" for this card\n is not sufficient for" | device_printf(dev, "For optimal performance a x8 PCIE, or x4 PCIE Gen2 slot is required.\n"); | ||||
" optimal performance.\n"); | |||||
device_printf(dev, "For optimal performance a x8 " | |||||
"PCIE, or x4 PCIE Gen2 slot is required.\n"); | |||||
} | } | ||||
if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) && | if ((hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) && | ||||
((hw->bus.width <= ixgbe_bus_width_pcie_x8) && | ((hw->bus.width <= ixgbe_bus_width_pcie_x8) && | ||||
(hw->bus.speed < ixgbe_bus_speed_8000))) { | (hw->bus.speed < ixgbe_bus_speed_8000))) { | ||||
device_printf(dev, "PCI-Express bandwidth available" | device_printf(dev, "PCI-Express bandwidth available for this card\n is not sufficient for optimal performance.\n"); | ||||
" for this card\n is not sufficient for" | device_printf(dev, "For optimal performance a x8 PCIE Gen3 slot is required.\n"); | ||||
" optimal performance.\n"); | |||||
device_printf(dev, "For optimal performance a x8 " | |||||
"PCIE Gen3 slot is required.\n"); | |||||
} | } | ||||
return; | return; | ||||
} | } /* ixgbe_get_slot_info */ | ||||
/* | /************************************************************************ | ||||
** Setup the correct IVAR register for a particular MSIX interrupt | * ixgbe_set_ivar | ||||
** (yes this is all very magic and confusing :) | * | ||||
** - entry is the register array entry | * Setup the correct IVAR register for a particular MSI-X interrupt | ||||
** - vector is the MSIX vector for this queue | * (yes this is all very magic and confusing :) | ||||
** - type is RX/TX/MISC | * - entry is the register array entry | ||||
*/ | * - vector is the MSI-X vector for this queue | ||||
* - type is RX/TX/MISC | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) | ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 ivar, index; | u32 ivar, index; | ||||
vector |= IXGBE_IVAR_ALLOC_VAL; | vector |= IXGBE_IVAR_ALLOC_VAL; | ||||
Show All 16 Lines | ixgbe_set_ivar(struct adapter *adapter, u8 entry, u8 vector, s8 type) | ||||
case ixgbe_mac_X550: | case ixgbe_mac_X550: | ||||
case ixgbe_mac_X550EM_x: | case ixgbe_mac_X550EM_x: | ||||
if (type == -1) { /* MISC IVAR */ | if (type == -1) { /* MISC IVAR */ | ||||
index = (entry & 1) * 8; | index = (entry & 1) * 8; | ||||
ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); | ivar = IXGBE_READ_REG(hw, IXGBE_IVAR_MISC); | ||||
ivar &= ~(0xFF << index); | ivar &= ~(0xFF << index); | ||||
ivar |= (vector << index); | ivar |= (vector << index); | ||||
IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); | IXGBE_WRITE_REG(hw, IXGBE_IVAR_MISC, ivar); | ||||
} else { /* RX/TX IVARS */ | } else { /* RX/TX IVARS */ | ||||
index = (16 * (entry & 1)) + (8 * type); | index = (16 * (entry & 1)) + (8 * type); | ||||
ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); | ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(entry >> 1)); | ||||
ivar &= ~(0xFF << index); | ivar &= ~(0xFF << index); | ||||
ivar |= (vector << index); | ivar |= (vector << index); | ||||
IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar); | IXGBE_WRITE_REG(hw, IXGBE_IVAR(entry >> 1), ivar); | ||||
} | } | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } /* ixgbe_set_ivar */ | ||||
/************************************************************************ | |||||
* ixgbe_configure_ivars | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_configure_ivars(struct adapter *adapter) | ixgbe_configure_ivars(struct adapter *adapter) | ||||
{ | { | ||||
struct ix_queue *que = adapter->queues; | struct ix_queue *que = adapter->queues; | ||||
u32 newitr; | u32 newitr; | ||||
if (ixgbe_max_interrupt_rate > 0) | if (ixgbe_max_interrupt_rate > 0) | ||||
newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; | newitr = (4000000 / ixgbe_max_interrupt_rate) & 0x0FF8; | ||||
else { | else { | ||||
/* | /* | ||||
** Disable DMA coalescing if interrupt moderation is | * Disable DMA coalescing if interrupt moderation is | ||||
** disabled. | * disabled. | ||||
*/ | */ | ||||
adapter->dmac = 0; | adapter->dmac = 0; | ||||
newitr = 0; | newitr = 0; | ||||
} | } | ||||
for (int i = 0; i < adapter->num_queues; i++, que++) { | for (int i = 0; i < adapter->num_queues; i++, que++) { | ||||
struct rx_ring *rxr = &adapter->rx_rings[i]; | struct rx_ring *rxr = &adapter->rx_rings[i]; | ||||
struct tx_ring *txr = &adapter->tx_rings[i]; | struct tx_ring *txr = &adapter->tx_rings[i]; | ||||
/* First the RX queue entry */ | /* First the RX queue entry */ | ||||
ixgbe_set_ivar(adapter, rxr->me, que->msix, 0); | ixgbe_set_ivar(adapter, rxr->me, que->msix, 0); | ||||
/* ... and the TX */ | /* ... and the TX */ | ||||
ixgbe_set_ivar(adapter, txr->me, que->msix, 1); | ixgbe_set_ivar(adapter, txr->me, que->msix, 1); | ||||
/* Set an Initial EITR value */ | /* Set an Initial EITR value */ | ||||
IXGBE_WRITE_REG(&adapter->hw, | IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(que->msix), newitr); | ||||
IXGBE_EITR(que->msix), newitr); | |||||
} | } | ||||
/* For the Link interrupt */ | /* For the Link interrupt */ | ||||
ixgbe_set_ivar(adapter, 1, adapter->vector, -1); | ixgbe_set_ivar(adapter, 1, adapter->vector, -1); | ||||
} | } /* ixgbe_configure_ivars */ | ||||
/* | /************************************************************************ | ||||
** ixgbe_sfp_probe - called in the local timer to | * ixgbe_sfp_probe | ||||
** determine if a port had optics inserted. | * | ||||
*/ | * Determine if a port had optics inserted. | ||||
************************************************************************/ | |||||
static bool | static bool | ||||
ixgbe_sfp_probe(struct adapter *adapter) | ixgbe_sfp_probe(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
bool result = FALSE; | bool result = FALSE; | ||||
if ((hw->phy.type == ixgbe_phy_nl) && | if ((hw->phy.type == ixgbe_phy_nl) && | ||||
(hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { | (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { | ||||
s32 ret = hw->phy.ops.identify_sfp(hw); | s32 ret = hw->phy.ops.identify_sfp(hw); | ||||
if (ret) | if (ret) | ||||
goto out; | goto out; | ||||
ret = hw->phy.ops.reset(hw); | ret = hw->phy.ops.reset(hw); | ||||
adapter->sfp_probe = FALSE; | |||||
if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { | if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { | ||||
device_printf(dev, "Unsupported SFP+ module detected!"); | device_printf(dev, "Unsupported SFP+ module detected!"); | ||||
device_printf(dev, "Reload driver with supported module.\n"); | device_printf(dev, | ||||
adapter->sfp_probe = FALSE; | "Reload driver with supported module.\n"); | ||||
goto out; | goto out; | ||||
} else | } else | ||||
device_printf(dev, "SFP+ module detected!\n"); | device_printf(dev, "SFP+ module detected!\n"); | ||||
/* We now have supported optics */ | /* We now have supported optics */ | ||||
adapter->sfp_probe = FALSE; | |||||
/* Set the optics type so system reports correctly */ | /* Set the optics type so system reports correctly */ | ||||
ixgbe_setup_optics(adapter); | ixgbe_setup_optics(adapter); | ||||
result = TRUE; | result = TRUE; | ||||
} | } | ||||
out: | out: | ||||
return (result); | return (result); | ||||
} | } /* ixgbe_sfp_probe */ | ||||
/* | /************************************************************************ | ||||
** Tasklet handler for MSIX Link interrupts | * ixgbe_handle_link - Tasklet for MSI-X Link interrupts | ||||
** - do outside interrupt since it might sleep | * | ||||
*/ | * Done outside of interrupt context since the driver might sleep | ||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_handle_link(void *context, int pending) | ixgbe_handle_link(void *context, int pending) | ||||
{ | { | ||||
struct adapter *adapter = context; | struct adapter *adapter = context; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
ixgbe_check_link(hw, | ixgbe_check_link(hw, &adapter->link_speed, &adapter->link_up, 0); | ||||
&adapter->link_speed, &adapter->link_up, 0); | |||||
ixgbe_update_link_status(adapter); | ixgbe_update_link_status(adapter); | ||||
/* Re-enable link interrupts */ | /* Re-enable link interrupts */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_LSC); | IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_LSC); | ||||
} | } /* ixgbe_handle_link */ | ||||
/* | /************************************************************************ | ||||
** Tasklet for handling SFP module interrupts | * ixgbe_handle_mod - Tasklet for SFP module interrupts | ||||
*/ | ************************************************************************/ | ||||
static void | static void | ||||
ixgbe_handle_mod(void *context, int pending) | ixgbe_handle_mod(void *context, int pending) | ||||
{ | { | ||||
struct adapter *adapter = context; | struct adapter *adapter = context; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
enum ixgbe_phy_type orig_type = hw->phy.type; | enum ixgbe_phy_type orig_type = hw->phy.type; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
u32 err; | u32 err; | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
/* Check to see if the PHY type changed */ | /* Check to see if the PHY type changed */ | ||||
if (hw->phy.ops.identify) { | if (hw->phy.ops.identify) { | ||||
hw->phy.type = ixgbe_phy_unknown; | hw->phy.type = ixgbe_phy_unknown; | ||||
hw->phy.ops.identify(hw); | hw->phy.ops.identify(hw); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | case ixgbe_media_type_cx4: | ||||
adapter->optics = IFM_10G_CX4; | adapter->optics = IFM_10G_CX4; | ||||
break; | break; | ||||
default: | default: | ||||
adapter->optics = 0; | adapter->optics = 0; | ||||
break; | break; | ||||
} | } | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
return; | return; | ||||
} | } /* ixgbe_handle_mod */ | ||||
/* | /************************************************************************ | ||||
** Tasklet for handling MSF (multispeed fiber) interrupts | * ixgbe_handle_msf - Tasklet for MSF (multispeed fiber) interrupts | ||||
*/ | ************************************************************************/ | ||||
static void | static void | ||||
ixgbe_handle_msf(void *context, int pending) | ixgbe_handle_msf(void *context, int pending) | ||||
{ | { | ||||
struct adapter *adapter = context; | struct adapter *adapter = context; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 autoneg; | u32 autoneg; | ||||
bool negotiate; | bool negotiate; | ||||
IXGBE_CORE_LOCK(adapter); | IXGBE_CORE_LOCK(adapter); | ||||
/* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */ | /* get_supported_phy_layer will call hw->phy.ops.identify_sfp() */ | ||||
adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); | adapter->phy_layer = ixgbe_get_supported_physical_layer(hw); | ||||
autoneg = hw->phy.autoneg_advertised; | autoneg = hw->phy.autoneg_advertised; | ||||
if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) | if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) | ||||
hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate); | hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiate); | ||||
if (hw->mac.ops.setup_link) | if (hw->mac.ops.setup_link) | ||||
hw->mac.ops.setup_link(hw, autoneg, TRUE); | hw->mac.ops.setup_link(hw, autoneg, TRUE); | ||||
/* Adjust media types shown in ifconfig */ | /* Adjust media types shown in ifconfig */ | ||||
ifmedia_removeall(&adapter->media); | ifmedia_removeall(&adapter->media); | ||||
ixgbe_add_media_types(adapter); | ixgbe_add_media_types(adapter); | ||||
IXGBE_CORE_UNLOCK(adapter); | IXGBE_CORE_UNLOCK(adapter); | ||||
return; | return; | ||||
} | } /* ixgbe_handle_msf */ | ||||
/* | /************************************************************************ | ||||
** Tasklet for handling interrupts from an external PHY | * ixgbe_handle_phy - Tasklet for external PHY interrupts | ||||
*/ | ************************************************************************/ | ||||
static void | static void | ||||
ixgbe_handle_phy(void *context, int pending) | ixgbe_handle_phy(void *context, int pending) | ||||
{ | { | ||||
struct adapter *adapter = context; | struct adapter *adapter = context; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
int error; | int error; | ||||
error = hw->phy.ops.handle_lasi(hw); | error = hw->phy.ops.handle_lasi(hw); | ||||
if (error == IXGBE_ERR_OVERTEMP) | if (error == IXGBE_ERR_OVERTEMP) | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, "CRITICAL: EXTERNAL PHY OVER TEMP!! PHY will downshift to lower power state!\n"); | ||||
"CRITICAL: EXTERNAL PHY OVER TEMP!! " | |||||
" PHY will downshift to lower power state!\n"); | |||||
else if (error) | else if (error) | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Error handling LASI interrupt: %d\n", | "Error handling LASI interrupt: %d\n", error); | ||||
error); | |||||
return; | return; | ||||
} | } /* ixgbe_handle_phy */ | ||||
#ifdef IXGBE_FDIR | #ifdef IXGBE_FDIR | ||||
/* | /* | ||||
** Tasklet for reinitializing the Flow Director filter table | ** Tasklet for reinitializing the Flow Director filter table | ||||
*/ | */ | ||||
static void | static void | ||||
ixgbe_reinit_fdir(void *context, int pending) | ixgbe_reinit_fdir(void *context, int pending) | ||||
{ | { | ||||
struct adapter *adapter = context; | struct adapter *adapter = context; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
if (adapter->fdir_reinit != 1) /* Shouldn't happen */ | if (adapter->fdir_reinit != 1) /* Shouldn't happen */ | ||||
return; | return; | ||||
ixgbe_reinit_fdir_tables_82599(&adapter->hw); | ixgbe_reinit_fdir_tables_82599(&adapter->hw); | ||||
adapter->fdir_reinit = 0; | adapter->fdir_reinit = 0; | ||||
/* re-enable flow director interrupts */ | /* re-enable flow director interrupts */ | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); | ||||
/* Restart the interface */ | /* Restart the interface */ | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | ifp->if_drv_flags |= IFF_DRV_RUNNING; | ||||
return; | return; | ||||
} | } | ||||
#endif | #endif | ||||
/********************************************************************* | /************************************************************************ | ||||
* | * ixgbe_config_dmac - Configure DMA Coalescing | ||||
* Configure DMA Coalescing | ************************************************************************/ | ||||
* | |||||
**********************************************************************/ | |||||
static void | static void | ||||
ixgbe_config_dmac(struct adapter *adapter) | ixgbe_config_dmac(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config; | struct ixgbe_dmac_config *dcfg = &hw->mac.dmac_config; | ||||
if (hw->mac.type < ixgbe_mac_X550 || | if (hw->mac.type < ixgbe_mac_X550 || !hw->mac.ops.dmac_config) | ||||
!hw->mac.ops.dmac_config) | |||||
return; | return; | ||||
if (dcfg->watchdog_timer ^ adapter->dmac || | if (dcfg->watchdog_timer ^ adapter->dmac || | ||||
dcfg->link_speed ^ adapter->link_speed) { | dcfg->link_speed ^ adapter->link_speed) { | ||||
dcfg->watchdog_timer = adapter->dmac; | dcfg->watchdog_timer = adapter->dmac; | ||||
dcfg->fcoe_en = false; | dcfg->fcoe_en = false; | ||||
dcfg->link_speed = adapter->link_speed; | dcfg->link_speed = adapter->link_speed; | ||||
dcfg->num_tcs = 1; | dcfg->num_tcs = 1; | ||||
INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n", | INIT_DEBUGOUT2("dmac settings: watchdog %d, link speed %d\n", | ||||
dcfg->watchdog_timer, dcfg->link_speed); | dcfg->watchdog_timer, dcfg->link_speed); | ||||
hw->mac.ops.dmac_config(hw); | hw->mac.ops.dmac_config(hw); | ||||
} | } | ||||
} | } /* ixgbe_config_dmac */ | ||||
/* | /************************************************************************ | ||||
* ixgbe_check_wol_support | |||||
* | |||||
* Checks whether the adapter's ports are capable of | * Checks whether the adapter's ports are capable of | ||||
* Wake On LAN by reading the adapter's NVM. | * Wake On LAN by reading the adapter's NVM. | ||||
* | * | ||||
* Sets each port's hw->wol_enabled value depending | * Sets each port's hw->wol_enabled value depending | ||||
* on the value read here. | * on the value read here. | ||||
*/ | ************************************************************************/ | ||||
static void | static void | ||||
ixgbe_check_wol_support(struct adapter *adapter) | ixgbe_check_wol_support(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u16 dev_caps = 0; | u16 dev_caps = 0; | ||||
/* Find out WoL support for port */ | /* Find out WoL support for port */ | ||||
adapter->wol_support = hw->wol_enabled = 0; | adapter->wol_support = hw->wol_enabled = 0; | ||||
ixgbe_get_device_caps(hw, &dev_caps); | ixgbe_get_device_caps(hw, &dev_caps); | ||||
if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) || | if ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0_1) || | ||||
((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) && | ((dev_caps & IXGBE_DEVICE_CAPS_WOL_PORT0) && | ||||
hw->bus.func == 0)) | hw->bus.func == 0)) | ||||
adapter->wol_support = hw->wol_enabled = 1; | adapter->wol_support = hw->wol_enabled = 1; | ||||
/* Save initial wake up filter configuration */ | /* Save initial wake up filter configuration */ | ||||
adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC); | adapter->wufc = IXGBE_READ_REG(hw, IXGBE_WUFC); | ||||
return; | return; | ||||
} | } /* ixgbe_check_wol_support */ | ||||
/* | /************************************************************************ | ||||
* ixgbe_setup_low_power_mode - LPLU/WoL preparation | |||||
* | |||||
* Prepare the adapter/port for LPLU and/or WoL | * Prepare the adapter/port for LPLU and/or WoL | ||||
*/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_setup_low_power_mode(struct adapter *adapter) | ixgbe_setup_low_power_mode(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
s32 error = 0; | s32 error = 0; | ||||
mtx_assert(&adapter->core_mtx, MA_OWNED); | mtx_assert(&adapter->core_mtx, MA_OWNED); | ||||
if (!hw->wol_enabled) | if (!hw->wol_enabled) | ||||
ixgbe_set_phy_power(hw, FALSE); | ixgbe_set_phy_power(hw, FALSE); | ||||
/* Limit power management flow to X550EM baseT */ | /* Limit power management flow to X550EM baseT */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && | ||||
&& hw->phy.ops.enter_lplu) { | hw->phy.ops.enter_lplu) { | ||||
/* Turn off support for APM wakeup. (Using ACPI instead) */ | /* Turn off support for APM wakeup. (Using ACPI instead) */ | ||||
IXGBE_WRITE_REG(hw, IXGBE_GRC, | IXGBE_WRITE_REG(hw, IXGBE_GRC, | ||||
IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2); | IXGBE_READ_REG(hw, IXGBE_GRC) & ~(u32)2); | ||||
/* | /* | ||||
* Clear Wake Up Status register to prevent any previous wakeup | * Clear Wake Up Status register to prevent any previous wakeup | ||||
* events from waking us up immediately after we suspend. | * events from waking us up immediately after we suspend. | ||||
*/ | */ | ||||
Show All 9 Lines | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T && | ||||
IXGBE_WRITE_REG(hw, IXGBE_WUC, | IXGBE_WRITE_REG(hw, IXGBE_WUC, | ||||
IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN); | IXGBE_WUC_WKEN | IXGBE_WUC_PME_EN); | ||||
/* X550EM baseT adapters need a special LPLU flow */ | /* X550EM baseT adapters need a special LPLU flow */ | ||||
hw->phy.reset_disable = true; | hw->phy.reset_disable = true; | ||||
ixgbe_stop(adapter); | ixgbe_stop(adapter); | ||||
error = hw->phy.ops.enter_lplu(hw); | error = hw->phy.ops.enter_lplu(hw); | ||||
if (error) | if (error) | ||||
device_printf(dev, | device_printf(dev, "Error entering LPLU: %d\n", error); | ||||
"Error entering LPLU: %d\n", error); | |||||
hw->phy.reset_disable = false; | hw->phy.reset_disable = false; | ||||
} else { | } else { | ||||
/* Just stop for other adapters */ | /* Just stop for other adapters */ | ||||
ixgbe_stop(adapter); | ixgbe_stop(adapter); | ||||
} | } | ||||
return error; | return error; | ||||
} | } /* ixgbe_setup_low_power_mode */ | ||||
/********************************************************************** | /************************************************************************ | ||||
* | * ixgbe_update_stats_counters - Update board statistics counters. | ||||
* Update the board statistics counters. | ************************************************************************/ | ||||
* | |||||
**********************************************************************/ | |||||
static void | static void | ||||
ixgbe_update_stats_counters(struct adapter *adapter) | ixgbe_update_stats_counters(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 missed_rx = 0, bprc, lxon, lxoff, total; | u32 missed_rx = 0, bprc, lxon, lxoff, total; | ||||
u64 total_missed_rx = 0; | u64 total_missed_rx = 0; | ||||
adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); | adapter->stats.pf.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); | ||||
adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); | adapter->stats.pf.illerrc += IXGBE_READ_REG(hw, IXGBE_ILLERRC); | ||||
adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); | adapter->stats.pf.errbc += IXGBE_READ_REG(hw, IXGBE_ERRBC); | ||||
adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); | adapter->stats.pf.mspdc += IXGBE_READ_REG(hw, IXGBE_MSPDC); | ||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); | adapter->stats.pf.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | ixgbe_update_stats_counters(struct adapter *adapter) | ||||
IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc); | IXGBE_SET_IBYTES(adapter, adapter->stats.pf.gorc); | ||||
IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc); | IXGBE_SET_OBYTES(adapter, adapter->stats.pf.gotc); | ||||
IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc); | IXGBE_SET_IMCASTS(adapter, adapter->stats.pf.mprc); | ||||
IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc); | IXGBE_SET_OMCASTS(adapter, adapter->stats.pf.mptc); | ||||
IXGBE_SET_COLLISIONS(adapter, 0); | IXGBE_SET_COLLISIONS(adapter, 0); | ||||
IXGBE_SET_IQDROPS(adapter, total_missed_rx); | IXGBE_SET_IQDROPS(adapter, total_missed_rx); | ||||
IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs | IXGBE_SET_IERRORS(adapter, adapter->stats.pf.crcerrs | ||||
+ adapter->stats.pf.rlec); | + adapter->stats.pf.rlec); | ||||
} | } /* ixgbe_update_stats_counters */ | ||||
#if __FreeBSD_version >= 1100036 | #if __FreeBSD_version >= 1100036 | ||||
/************************************************************************ | |||||
* ixgbe_get_counter | |||||
************************************************************************/ | |||||
static uint64_t | static uint64_t | ||||
ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt) | ixgbe_get_counter(struct ifnet *ifp, ift_counter cnt) | ||||
{ | { | ||||
struct adapter *adapter; | struct adapter *adapter; | ||||
struct tx_ring *txr; | struct tx_ring *txr; | ||||
uint64_t rv; | uint64_t rv; | ||||
adapter = if_getsoftc(ifp); | adapter = if_getsoftc(ifp); | ||||
switch (cnt) { | switch (cnt) { | ||||
case IFCOUNTER_IPACKETS: | case IFCOUNTER_IPACKETS: | ||||
return (adapter->ipackets); | return (adapter->ipackets); | ||||
case IFCOUNTER_OPACKETS: | case IFCOUNTER_OPACKETS: | ||||
return (adapter->opackets); | return (adapter->opackets); | ||||
Show All 15 Lines | case IFCOUNTER_OQDROPS: | ||||
for (int i = 0; i < adapter->num_queues; i++, txr++) | for (int i = 0; i < adapter->num_queues; i++, txr++) | ||||
rv += txr->br->br_drops; | rv += txr->br->br_drops; | ||||
return (rv); | return (rv); | ||||
case IFCOUNTER_IERRORS: | case IFCOUNTER_IERRORS: | ||||
return (adapter->ierrors); | return (adapter->ierrors); | ||||
default: | default: | ||||
return (if_get_counter_default(ifp, cnt)); | return (if_get_counter_default(ifp, cnt)); | ||||
} | } | ||||
} | } /* ixgbe_get_counter */ | ||||
#endif | #endif | ||||
/** ixgbe_sysctl_tdh_handler - Handler function | /************************************************************************ | ||||
* ixgbe_sysctl_tdh_handler - Transmit Descriptor Head handler function | |||||
* | |||||
* Retrieves the TDH value from the hardware | * Retrieves the TDH value from the hardware | ||||
*/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_tdh_handler(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
int error; | int error; | ||||
struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); | struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); | ||||
if (!txr) return 0; | |||||
if (!txr) | |||||
return 0; | |||||
unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); | unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDH(txr->me)); | ||||
error = sysctl_handle_int(oidp, &val, 0, req); | error = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (error || !req->newptr) | if (error || !req->newptr) | ||||
return error; | return error; | ||||
return 0; | return 0; | ||||
} | } /* ixgbe_sysctl_tdh_handler */ | ||||
/** ixgbe_sysctl_tdt_handler - Handler function | /************************************************************************ | ||||
* ixgbe_sysctl_tdt_handler - Transmit Descriptor Tail handler function | |||||
* | |||||
* Retrieves the TDT value from the hardware | * Retrieves the TDT value from the hardware | ||||
*/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_tdt_handler(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
int error; | int error; | ||||
struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); | struct tx_ring *txr = ((struct tx_ring *)oidp->oid_arg1); | ||||
if (!txr) return 0; | |||||
if (!txr) | |||||
return 0; | |||||
unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); | unsigned val = IXGBE_READ_REG(&txr->adapter->hw, IXGBE_TDT(txr->me)); | ||||
error = sysctl_handle_int(oidp, &val, 0, req); | error = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (error || !req->newptr) | if (error || !req->newptr) | ||||
return error; | return error; | ||||
return 0; | return 0; | ||||
} | } /* ixgbe_sysctl_tdt_handler */ | ||||
/** ixgbe_sysctl_rdh_handler - Handler function | /************************************************************************ | ||||
* ixgbe_sysctl_rdh_handler - Receive Descriptor Head handler function | |||||
* | |||||
* Retrieves the RDH value from the hardware | * Retrieves the RDH value from the hardware | ||||
*/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_rdh_handler(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
int error; | int error; | ||||
struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); | struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); | ||||
if (!rxr) return 0; | |||||
if (!rxr) | |||||
return 0; | |||||
unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); | unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDH(rxr->me)); | ||||
error = sysctl_handle_int(oidp, &val, 0, req); | error = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (error || !req->newptr) | if (error || !req->newptr) | ||||
return error; | return error; | ||||
return 0; | return 0; | ||||
} | } /* ixgbe_sysctl_rdh_handler */ | ||||
/** ixgbe_sysctl_rdt_handler - Handler function | /************************************************************************ | ||||
* ixgbe_sysctl_rdt_handler - Receive Descriptor Tail handler function | |||||
* | |||||
* Retrieves the RDT value from the hardware | * Retrieves the RDT value from the hardware | ||||
*/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_rdt_handler(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
int error; | int error; | ||||
struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); | struct rx_ring *rxr = ((struct rx_ring *)oidp->oid_arg1); | ||||
if (!rxr) return 0; | |||||
if (!rxr) | |||||
return 0; | |||||
unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); | unsigned val = IXGBE_READ_REG(&rxr->adapter->hw, IXGBE_RDT(rxr->me)); | ||||
error = sysctl_handle_int(oidp, &val, 0, req); | error = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (error || !req->newptr) | if (error || !req->newptr) | ||||
return error; | return error; | ||||
return 0; | return 0; | ||||
} | } /* ixgbe_sysctl_rdt_handler */ | ||||
/************************************************************************ | |||||
* ixgbe_sysctl_interrupt_rate_handler | |||||
************************************************************************/ | |||||
static int | static int | ||||
ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_interrupt_rate_handler(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
int error; | |||||
struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1); | struct ix_queue *que = ((struct ix_queue *)oidp->oid_arg1); | ||||
int error; | |||||
unsigned int reg, usec, rate; | unsigned int reg, usec, rate; | ||||
reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix)); | reg = IXGBE_READ_REG(&que->adapter->hw, IXGBE_EITR(que->msix)); | ||||
usec = ((reg & 0x0FF8) >> 3); | usec = ((reg & 0x0FF8) >> 3); | ||||
if (usec > 0) | if (usec > 0) | ||||
rate = 500000 / usec; | rate = 500000 / usec; | ||||
else | else | ||||
rate = 0; | rate = 0; | ||||
error = sysctl_handle_int(oidp, &rate, 0, req); | error = sysctl_handle_int(oidp, &rate, 0, req); | ||||
if (error || !req->newptr) | if (error || !req->newptr) | ||||
return error; | return error; | ||||
reg &= ~0xfff; /* default, no limitation */ | reg &= ~0xfff; /* default, no limitation */ | ||||
ixgbe_max_interrupt_rate = 0; | ixgbe_max_interrupt_rate = 0; | ||||
if (rate > 0 && rate < 500000) { | if (rate > 0 && rate < 500000) { | ||||
if (rate < 1000) | if (rate < 1000) | ||||
rate = 1000; | rate = 1000; | ||||
ixgbe_max_interrupt_rate = rate; | ixgbe_max_interrupt_rate = rate; | ||||
reg |= ((4000000/rate) & 0xff8 ); | reg |= ((4000000/rate) & 0xff8 ); | ||||
} | } | ||||
IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg); | IXGBE_WRITE_REG(&que->adapter->hw, IXGBE_EITR(que->msix), reg); | ||||
return 0; | return 0; | ||||
} | } /* ixgbe_sysctl_interrupt_rate_handler */ | ||||
/************************************************************************ | |||||
* ixgbe_add_device_sysctls | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_add_device_sysctls(struct adapter *adapter) | ixgbe_add_device_sysctls(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 sysctl_oid_list *child; | struct sysctl_oid_list *child; | ||||
struct sysctl_ctx_list *ctx; | struct sysctl_ctx_list *ctx; | ||||
ctx = device_get_sysctl_ctx(dev); | ctx = device_get_sysctl_ctx(dev); | ||||
child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); | child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); | ||||
/* Sysctls for all devices */ | /* Sysctls for all devices */ | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, | ||||
CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | adapter, 0, ixgbe_sysctl_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC); | ||||
ixgbe_sysctl_flowcntl, "I", IXGBE_SYSCTL_DESC_SET_FC); | |||||
SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim", | SYSCTL_ADD_INT(ctx, child, OID_AUTO, "enable_aim", CTLFLAG_RW, | ||||
CTLFLAG_RW, | |||||
&ixgbe_enable_aim, 1, "Interrupt Moderation"); | &ixgbe_enable_aim, 1, "Interrupt Moderation"); | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "advertise_speed", | ||||
CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixgbe_sysctl_advertise, "I", | ||||
ixgbe_sysctl_advertise, "I", IXGBE_SYSCTL_DESC_ADV_SPEED); | IXGBE_SYSCTL_DESC_ADV_SPEED); | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "thermal_test", | ||||
CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixgbe_sysctl_thermal_test, | ||||
ixgbe_sysctl_thermal_test, "I", "Thermal Test"); | "I", "Thermal Test"); | ||||
#ifdef IXGBE_DEBUG | #ifdef IXGBE_DEBUG | ||||
/* testing sysctls (for all devices) */ | /* testing sysctls (for all devices) */ | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "power_state", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "power_state", | ||||
CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixgbe_sysctl_power_state, | ||||
ixgbe_sysctl_power_state, "I", "PCI Power State"); | "I", "PCI Power State"); | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "print_rss_config", | ||||
CTLTYPE_STRING | CTLFLAG_RD, adapter, 0, | CTLTYPE_STRING | CTLFLAG_RD, adapter, 0, | ||||
ixgbe_sysctl_print_rss_config, "A", "Prints RSS Configuration"); | ixgbe_sysctl_print_rss_config, "A", "Prints RSS Configuration"); | ||||
#endif | #endif | ||||
/* for X550 series devices */ | /* for X550 series devices */ | ||||
if (hw->mac.type >= ixgbe_mac_X550) | if (hw->mac.type >= ixgbe_mac_X550) | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "dmac", | ||||
CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixgbe_sysctl_dmac, | ||||
ixgbe_sysctl_dmac, "I", "DMA Coalesce"); | "I", "DMA Coalesce"); | ||||
/* for X552 backplane devices */ | /* for X552 backplane devices */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { | ||||
struct sysctl_oid *eee_node; | struct sysctl_oid *eee_node; | ||||
struct sysctl_oid_list *eee_list; | struct sysctl_oid_list *eee_list; | ||||
eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee", | eee_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "eee", | ||||
CTLFLAG_RD, NULL, | CTLFLAG_RD, NULL, | ||||
Show All 24 Lines | SYSCTL_ADD_PROC(ctx, eee_list, OID_AUTO, "tx_lpi_delay", | ||||
CTLTYPE_INT | CTLFLAG_RD, adapter, 0, | CTLTYPE_INT | CTLFLAG_RD, adapter, 0, | ||||
ixgbe_sysctl_eee_tx_lpi_delay, "I", | ixgbe_sysctl_eee_tx_lpi_delay, "I", | ||||
"TX LPI entry delay in microseconds"); | "TX LPI entry delay in microseconds"); | ||||
} | } | ||||
/* for WoL-capable devices */ | /* for WoL-capable devices */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { | ||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wol_enable", | ||||
CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | ||||
ixgbe_sysctl_wol_enable, "I", | ixgbe_sysctl_wol_enable, "I", "Enable/Disable Wake on LAN"); | ||||
"Enable/Disable Wake on LAN"); | |||||
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc", | SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "wufc", | ||||
CTLTYPE_INT | CTLFLAG_RW, adapter, 0, | CTLTYPE_INT | CTLFLAG_RW, adapter, 0, ixgbe_sysctl_wufc, | ||||
ixgbe_sysctl_wufc, "I", | "I", "Enable/Disable Wake Up Filters"); | ||||
"Enable/Disable Wake Up Filters"); | |||||
} | } | ||||
/* for X552/X557-AT devices */ | /* for X552/X557-AT devices */ | ||||
if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { | if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { | ||||
struct sysctl_oid *phy_node; | struct sysctl_oid *phy_node; | ||||
struct sysctl_oid_list *phy_list; | struct sysctl_oid_list *phy_list; | ||||
phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy", | phy_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "phy", | ||||
CTLFLAG_RD, NULL, | CTLFLAG_RD, NULL, "External PHY sysctls"); | ||||
"External PHY sysctls"); | |||||
phy_list = SYSCTL_CHILDREN(phy_node); | phy_list = SYSCTL_CHILDREN(phy_node); | ||||
SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp", | SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "temp", | ||||
CTLTYPE_INT | CTLFLAG_RD, adapter, 0, | CTLTYPE_INT | CTLFLAG_RD, adapter, 0, ixgbe_sysctl_phy_temp, | ||||
ixgbe_sysctl_phy_temp, "I", | "I", "Current External PHY Temperature (Celsius)"); | ||||
"Current External PHY Temperature (Celsius)"); | |||||
SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred", | SYSCTL_ADD_PROC(ctx, phy_list, OID_AUTO, "overtemp_occurred", | ||||
CTLTYPE_INT | CTLFLAG_RD, adapter, 0, | CTLTYPE_INT | CTLFLAG_RD, adapter, 0, | ||||
ixgbe_sysctl_phy_overtemp_occurred, "I", | ixgbe_sysctl_phy_overtemp_occurred, "I", | ||||
"External PHY High Temperature Event Occurred"); | "External PHY High Temperature Event Occurred"); | ||||
} | } | ||||
} | } /* ixgbe_add_device_sysctls */ | ||||
/* | /************************************************************************ | ||||
* ixgbe_add_hw_stats | |||||
* | |||||
* Add sysctl variables, one per statistic, to the system. | * Add sysctl variables, one per statistic, to the system. | ||||
*/ | ************************************************************************/ | ||||
static void | static void | ||||
ixgbe_add_hw_stats(struct adapter *adapter) | ixgbe_add_hw_stats(struct adapter *adapter) | ||||
{ | { | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
struct tx_ring *txr = adapter->tx_rings; | struct tx_ring *txr = adapter->tx_rings; | ||||
struct rx_ring *rxr = adapter->rx_rings; | struct rx_ring *rxr = adapter->rx_rings; | ||||
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 ixgbe_hw_stats *stats = &adapter->stats.pf; | struct ixgbe_hw_stats *stats = &adapter->stats.pf; | ||||
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", | SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "dropped", | ||||
CTLFLAG_RD, &adapter->dropped_pkts, | CTLFLAG_RD, &adapter->dropped_pkts, "Driver dropped packets"); | ||||
"Driver dropped packets"); | |||||
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", | SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "mbuf_defrag_failed", | ||||
CTLFLAG_RD, &adapter->mbuf_defrag_failed, | CTLFLAG_RD, &adapter->mbuf_defrag_failed, "m_defrag() failed"); | ||||
"m_defrag() failed"); | |||||
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", | SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "watchdog_events", | ||||
CTLFLAG_RD, &adapter->watchdog_events, | CTLFLAG_RD, &adapter->watchdog_events, "Watchdog timeouts"); | ||||
"Watchdog timeouts"); | |||||
SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", | SYSCTL_ADD_ULONG(ctx, child, OID_AUTO, "link_irq", | ||||
CTLFLAG_RD, &adapter->link_irq, | CTLFLAG_RD, &adapter->link_irq, "Link MSI-X IRQ Handled"); | ||||
"Link MSIX IRQ Handled"); | |||||
for (int i = 0; i < adapter->num_queues; i++, txr++) { | for (int i = 0; i < adapter->num_queues; i++, 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_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", | SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "interrupt_rate", | ||||
CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i], | CTLTYPE_UINT | CTLFLAG_RW, &adapter->queues[i], | ||||
sizeof(&adapter->queues[i]), | sizeof(&adapter->queues[i]), | ||||
ixgbe_sysctl_interrupt_rate_handler, "IU", | ixgbe_sysctl_interrupt_rate_handler, "IU", | ||||
"Interrupt Rate"); | "Interrupt Rate"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", | ||||
CTLFLAG_RD, &(adapter->queues[i].irqs), | CTLFLAG_RD, &(adapter->queues[i].irqs), | ||||
"irqs on this queue"); | "irqs on this queue"); | ||||
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", | SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", | ||||
CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), | CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), | ||||
ixgbe_sysctl_tdh_handler, "IU", | ixgbe_sysctl_tdh_handler, "IU", "Transmit Descriptor Head"); | ||||
"Transmit Descriptor Head"); | |||||
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", | SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_tail", | ||||
CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), | CTLTYPE_UINT | CTLFLAG_RD, txr, sizeof(txr), | ||||
ixgbe_sysctl_tdt_handler, "IU", | ixgbe_sysctl_tdt_handler, "IU", "Transmit Descriptor Tail"); | ||||
"Transmit Descriptor Tail"); | |||||
SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", | SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "tso_tx", | ||||
CTLFLAG_RD, &txr->tso_tx, | CTLFLAG_RD, &txr->tso_tx, "TSO"); | ||||
"TSO"); | |||||
SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", | SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_tx_dma_setup", | ||||
CTLFLAG_RD, &txr->no_tx_dma_setup, | CTLFLAG_RD, &txr->no_tx_dma_setup, | ||||
"Driver tx dma failure in xmit"); | "Driver tx dma failure in xmit"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", | ||||
CTLFLAG_RD, &txr->no_desc_avail, | CTLFLAG_RD, &txr->no_desc_avail, | ||||
"Queue No Descriptor Available"); | "Queue No Descriptor Available"); | ||||
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, | CTLFLAG_RD, &txr->total_packets, | ||||
"Queue Packets Transmitted"); | "Queue Packets Transmitted"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "br_drops", | ||||
CTLFLAG_RD, &txr->br->br_drops, | CTLFLAG_RD, &txr->br->br_drops, | ||||
"Packets dropped in buf_ring"); | "Packets dropped in buf_ring"); | ||||
} | } | ||||
for (int i = 0; i < adapter->num_queues; i++, rxr++) { | for (int i = 0; i < adapter->num_queues; i++, 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); | ||||
struct lro_ctrl *lro = &rxr->lro; | struct lro_ctrl *lro = &rxr->lro; | ||||
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_PROC(ctx, queue_list, OID_AUTO, "rxd_head", | SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", | ||||
CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), | CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), | ||||
ixgbe_sysctl_rdh_handler, "IU", | ixgbe_sysctl_rdh_handler, "IU", "Receive Descriptor Head"); | ||||
"Receive Descriptor Head"); | |||||
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", | SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_tail", | ||||
CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), | CTLTYPE_UINT | CTLFLAG_RD, rxr, sizeof(rxr), | ||||
ixgbe_sysctl_rdt_handler, "IU", | ixgbe_sysctl_rdt_handler, "IU", "Receive Descriptor Tail"); | ||||
"Receive Descriptor Tail"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", | ||||
CTLFLAG_RD, &rxr->rx_packets, | CTLFLAG_RD, &rxr->rx_packets, "Queue Packets Received"); | ||||
"Queue Packets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", | ||||
CTLFLAG_RD, &rxr->rx_bytes, | CTLFLAG_RD, &rxr->rx_bytes, "Queue Bytes Received"); | ||||
"Queue Bytes Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_copies", | ||||
CTLFLAG_RD, &rxr->rx_copies, | CTLFLAG_RD, &rxr->rx_copies, "Copied RX Frames"); | ||||
"Copied RX Frames"); | |||||
SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_queued", | SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_queued", | ||||
CTLFLAG_RD, &lro->lro_queued, 0, | CTLFLAG_RD, &lro->lro_queued, 0, "LRO Queued"); | ||||
"LRO Queued"); | |||||
SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_flushed", | SYSCTL_ADD_U64(ctx, queue_list, OID_AUTO, "lro_flushed", | ||||
CTLFLAG_RD, &lro->lro_flushed, 0, | CTLFLAG_RD, &lro->lro_flushed, 0, "LRO Flushed"); | ||||
"LRO Flushed"); | |||||
} | } | ||||
/* MAC stats get the own sub node */ | /* MAC stats get the own sub node */ | ||||
stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", | stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac_stats", | ||||
CTLFLAG_RD, NULL, "MAC Statistics"); | CTLFLAG_RD, NULL, "MAC Statistics"); | ||||
stat_list = SYSCTL_CHILDREN(stat_node); | stat_list = SYSCTL_CHILDREN(stat_node); | ||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "crc_errs", | ||||
CTLFLAG_RD, &stats->crcerrs, | CTLFLAG_RD, &stats->crcerrs, "CRC Errors"); | ||||
"CRC Errors"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "ill_errs", | ||||
CTLFLAG_RD, &stats->illerrc, | CTLFLAG_RD, &stats->illerrc, "Illegal Byte Errors"); | ||||
"Illegal Byte Errors"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "byte_errs", | ||||
CTLFLAG_RD, &stats->errbc, | CTLFLAG_RD, &stats->errbc, "Byte Errors"); | ||||
"Byte Errors"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "short_discards", | ||||
CTLFLAG_RD, &stats->mspdc, | CTLFLAG_RD, &stats->mspdc, "MAC Short Packets Discarded"); | ||||
"MAC Short Packets Discarded"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "local_faults", | ||||
CTLFLAG_RD, &stats->mlfc, | CTLFLAG_RD, &stats->mlfc, "MAC Local Faults"); | ||||
"MAC Local Faults"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "remote_faults", | ||||
CTLFLAG_RD, &stats->mrfc, | CTLFLAG_RD, &stats->mrfc, "MAC Remote Faults"); | ||||
"MAC Remote Faults"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rec_len_errs", | ||||
CTLFLAG_RD, &stats->rlec, | CTLFLAG_RD, &stats->rlec, "Receive Length Errors"); | ||||
"Receive Length Errors"); | |||||
/* Flow Control stats */ | /* Flow Control stats */ | ||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_txd", | ||||
CTLFLAG_RD, &stats->lxontxc, | CTLFLAG_RD, &stats->lxontxc, "Link XON Transmitted"); | ||||
"Link XON Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xon_recvd", | ||||
CTLFLAG_RD, &stats->lxonrxc, | CTLFLAG_RD, &stats->lxonrxc, "Link XON Received"); | ||||
"Link XON Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_txd", | ||||
CTLFLAG_RD, &stats->lxofftxc, | CTLFLAG_RD, &stats->lxofftxc, "Link XOFF Transmitted"); | ||||
"Link XOFF Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "xoff_recvd", | ||||
CTLFLAG_RD, &stats->lxoffrxc, | CTLFLAG_RD, &stats->lxoffrxc, "Link XOFF Received"); | ||||
"Link XOFF Received"); | |||||
/* Packet Reception Stats */ | /* Packet Reception Stats */ | ||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_octets_rcvd", | ||||
CTLFLAG_RD, &stats->tor, | CTLFLAG_RD, &stats->tor, "Total Octets Received"); | ||||
"Total Octets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_rcvd", | ||||
CTLFLAG_RD, &stats->gorc, | CTLFLAG_RD, &stats->gorc, "Good Octets Received"); | ||||
"Good Octets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_rcvd", | ||||
CTLFLAG_RD, &stats->tpr, | CTLFLAG_RD, &stats->tpr, "Total Packets Received"); | ||||
"Total Packets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_rcvd", | ||||
CTLFLAG_RD, &stats->gprc, | CTLFLAG_RD, &stats->gprc, "Good Packets Received"); | ||||
"Good Packets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_rcvd", | ||||
CTLFLAG_RD, &stats->mprc, | CTLFLAG_RD, &stats->mprc, "Multicast Packets Received"); | ||||
"Multicast Packets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_rcvd", | ||||
CTLFLAG_RD, &stats->bprc, | CTLFLAG_RD, &stats->bprc, "Broadcast Packets Received"); | ||||
"Broadcast Packets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_64", | ||||
CTLFLAG_RD, &stats->prc64, | CTLFLAG_RD, &stats->prc64, "64 byte frames received "); | ||||
"64 byte frames received "); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_65_127", | ||||
CTLFLAG_RD, &stats->prc127, | CTLFLAG_RD, &stats->prc127, "65-127 byte frames received"); | ||||
"65-127 byte frames received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_128_255", | ||||
CTLFLAG_RD, &stats->prc255, | CTLFLAG_RD, &stats->prc255, "128-255 byte frames received"); | ||||
"128-255 byte frames received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_256_511", | ||||
CTLFLAG_RD, &stats->prc511, | CTLFLAG_RD, &stats->prc511, "256-511 byte frames received"); | ||||
"256-511 byte frames received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_512_1023", | ||||
CTLFLAG_RD, &stats->prc1023, | CTLFLAG_RD, &stats->prc1023, "512-1023 byte frames received"); | ||||
"512-1023 byte frames received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "rx_frames_1024_1522", | ||||
CTLFLAG_RD, &stats->prc1522, | CTLFLAG_RD, &stats->prc1522, "1023-1522 byte frames received"); | ||||
"1023-1522 byte frames received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_undersized", | ||||
CTLFLAG_RD, &stats->ruc, | CTLFLAG_RD, &stats->ruc, "Receive Undersized"); | ||||
"Receive Undersized"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_fragmented", | ||||
CTLFLAG_RD, &stats->rfc, | CTLFLAG_RD, &stats->rfc, "Fragmented Packets Received "); | ||||
"Fragmented Packets Received "); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_oversized", | ||||
CTLFLAG_RD, &stats->roc, | CTLFLAG_RD, &stats->roc, "Oversized Packets Received"); | ||||
"Oversized Packets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "recv_jabberd", | ||||
CTLFLAG_RD, &stats->rjc, | CTLFLAG_RD, &stats->rjc, "Received Jabber"); | ||||
"Received Jabber"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_rcvd", | ||||
CTLFLAG_RD, &stats->mngprc, | CTLFLAG_RD, &stats->mngprc, "Management Packets Received"); | ||||
"Management Packets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_drpd", | ||||
CTLFLAG_RD, &stats->mngptc, | CTLFLAG_RD, &stats->mngptc, "Management Packets Dropped"); | ||||
"Management Packets Dropped"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "checksum_errs", | ||||
CTLFLAG_RD, &stats->xec, | CTLFLAG_RD, &stats->xec, "Checksum Errors"); | ||||
"Checksum Errors"); | |||||
/* Packet Transmission Stats */ | /* Packet Transmission Stats */ | ||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_octets_txd", | ||||
CTLFLAG_RD, &stats->gotc, | CTLFLAG_RD, &stats->gotc, "Good Octets Transmitted"); | ||||
"Good Octets Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "total_pkts_txd", | ||||
CTLFLAG_RD, &stats->tpt, | CTLFLAG_RD, &stats->tpt, "Total Packets Transmitted"); | ||||
"Total Packets Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "good_pkts_txd", | ||||
CTLFLAG_RD, &stats->gptc, | CTLFLAG_RD, &stats->gptc, "Good Packets Transmitted"); | ||||
"Good Packets Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "bcast_pkts_txd", | ||||
CTLFLAG_RD, &stats->bptc, | CTLFLAG_RD, &stats->bptc, "Broadcast Packets Transmitted"); | ||||
"Broadcast Packets Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "mcast_pkts_txd", | ||||
CTLFLAG_RD, &stats->mptc, | CTLFLAG_RD, &stats->mptc, "Multicast Packets Transmitted"); | ||||
"Multicast Packets Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "management_pkts_txd", | ||||
CTLFLAG_RD, &stats->mngptc, | CTLFLAG_RD, &stats->mngptc, "Management Packets Transmitted"); | ||||
"Management Packets Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_64", | ||||
CTLFLAG_RD, &stats->ptc64, | CTLFLAG_RD, &stats->ptc64, "64 byte frames transmitted "); | ||||
"64 byte frames transmitted "); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_65_127", | ||||
CTLFLAG_RD, &stats->ptc127, | CTLFLAG_RD, &stats->ptc127, "65-127 byte frames transmitted"); | ||||
"65-127 byte frames transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_128_255", | ||||
CTLFLAG_RD, &stats->ptc255, | CTLFLAG_RD, &stats->ptc255, "128-255 byte frames transmitted"); | ||||
"128-255 byte frames transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_256_511", | ||||
CTLFLAG_RD, &stats->ptc511, | CTLFLAG_RD, &stats->ptc511, "256-511 byte frames transmitted"); | ||||
"256-511 byte frames transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_512_1023", | ||||
CTLFLAG_RD, &stats->ptc1023, | CTLFLAG_RD, &stats->ptc1023, "512-1023 byte frames transmitted"); | ||||
"512-1023 byte frames transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", | SYSCTL_ADD_UQUAD(ctx, stat_list, OID_AUTO, "tx_frames_1024_1522", | ||||
CTLFLAG_RD, &stats->ptc1522, | CTLFLAG_RD, &stats->ptc1522, "1024-1522 byte frames transmitted"); | ||||
"1024-1522 byte frames transmitted"); | } /* ixgbe_add_hw_stats */ | ||||
} | |||||
/************************************************************************ | |||||
* ixgbe_set_sysctl_value | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_set_sysctl_value(struct adapter *adapter, const char *name, | ixgbe_set_sysctl_value(struct adapter *adapter, const char *name, | ||||
const char *description, int *limit, int value) | const char *description, int *limit, int value) | ||||
{ | { | ||||
*limit = value; | *limit = value; | ||||
SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev), | SYSCTL_ADD_INT(device_get_sysctl_ctx(adapter->dev), | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), | SYSCTL_CHILDREN(device_get_sysctl_tree(adapter->dev)), | ||||
OID_AUTO, name, CTLFLAG_RW, limit, value, description); | OID_AUTO, name, CTLFLAG_RW, limit, value, description); | ||||
} | } /* ixgbe_set_sysctl_value */ | ||||
/* | /* | ||||
** Set flow control using sysctl: | ** Set flow control using sysctl: | ||||
** Flow control values: | ** Flow control values: | ||||
** 0 - off | ** 0 - off | ||||
** 1 - rx pause | ** 1 - rx pause | ||||
** 2 - tx pause | ** 2 - tx pause | ||||
** 3 - full | ** 3 - full | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | ixgbe_set_advertise(struct adapter *adapter, int advertise) | ||||
hw = &adapter->hw; | hw = &adapter->hw; | ||||
dev = adapter->dev; | dev = adapter->dev; | ||||
/* No speed changes for backplane media */ | /* No speed changes for backplane media */ | ||||
if (hw->phy.media_type == ixgbe_media_type_backplane) | if (hw->phy.media_type == ixgbe_media_type_backplane) | ||||
return (ENODEV); | return (ENODEV); | ||||
if (!((hw->phy.media_type == ixgbe_media_type_copper) || | if (!((hw->phy.media_type == ixgbe_media_type_copper) || | ||||
(hw->phy.multispeed_fiber))) { | (hw->phy.multispeed_fiber))) { | ||||
device_printf(dev, | device_printf(dev, "Advertised speed can only be set on copper or multispeed fiber media types.\n"); | ||||
"Advertised speed can only be set on copper or " | |||||
"multispeed fiber media types.\n"); | |||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if (advertise < 0x1 || advertise > 0x7) { | if (advertise < 0x1 || advertise > 0x7) { | ||||
device_printf(dev, | device_printf(dev, "Invalid advertised speed; valid modes are 0x1 through 0x7\n"); | ||||
"Invalid advertised speed; valid modes are 0x1 through 0x7\n"); | |||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if ((advertise & 0x1) | if ((advertise & 0x1) | ||||
&& (hw->mac.type != ixgbe_mac_X540) | && (hw->mac.type != ixgbe_mac_X540) | ||||
&& (hw->mac.type != ixgbe_mac_X550)) { | && (hw->mac.type != ixgbe_mac_X550)) { | ||||
device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n"); | device_printf(dev, "Set Advertise: 100Mb on X540/X550 only\n"); | ||||
return (EINVAL); | return (EINVAL); | ||||
Show All 10 Lines | ixgbe_set_advertise(struct adapter *adapter, int advertise) | ||||
adapter->advertise = advertise; | adapter->advertise = advertise; | ||||
hw->mac.autotry_restart = TRUE; | hw->mac.autotry_restart = TRUE; | ||||
hw->mac.ops.setup_link(hw, speed, TRUE); | hw->mac.ops.setup_link(hw, speed, TRUE); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /************************************************************************ | ||||
* The following two sysctls are for X552/X557-AT devices; | * ixgbe_sysctl_phy_temp - Retrieve temperature of PHY | ||||
* they deal with the external PHY used in them. | * | ||||
*/ | * For X552/X557-AT devices using an external PHY | ||||
************************************************************************/ | |||||
static int | static int | ||||
ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_phy_temp(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *adapter = (struct adapter *) arg1; | struct adapter *adapter = (struct adapter *) arg1; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u16 reg; | u16 reg; | ||||
if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { | if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Device has no supported external thermal sensor.\n"); | "Device has no supported external thermal sensor.\n"); | ||||
return (ENODEV); | return (ENODEV); | ||||
} | } | ||||
if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP, | if (hw->phy.ops.read_reg(hw, IXGBE_PHY_CURRENT_TEMP, | ||||
IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, | IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, ®)) { | ||||
®)) { | |||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Error reading from PHY's current temperature register\n"); | "Error reading from PHY's current temperature register\n"); | ||||
return (EAGAIN); | return (EAGAIN); | ||||
} | } | ||||
/* Shift temp for output */ | /* Shift temp for output */ | ||||
reg = reg >> 8; | reg = reg >> 8; | ||||
return (sysctl_handle_int(oidp, NULL, reg, req)); | return (sysctl_handle_int(oidp, NULL, reg, req)); | ||||
} | } /* ixgbe_sysctl_phy_temp */ | ||||
/* | /************************************************************************ | ||||
* Reports whether the current PHY temperature is over | * ixgbe_sysctl_phy_overtemp_occurred | ||||
* the overtemp threshold. | * | ||||
* - This is reported directly from the PHY | * Reports (directly from the PHY) whether the current PHY | ||||
*/ | * temperature is over the overtemp threshold. | ||||
************************************************************************/ | |||||
static int | static int | ||||
ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_phy_overtemp_occurred(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *adapter = (struct adapter *) arg1; | struct adapter *adapter = (struct adapter *) arg1; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u16 reg; | u16 reg; | ||||
if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { | if (hw->device_id != IXGBE_DEV_ID_X550EM_X_10G_T) { | ||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Device has no supported external thermal sensor.\n"); | "Device has no supported external thermal sensor.\n"); | ||||
return (ENODEV); | return (ENODEV); | ||||
} | } | ||||
if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS, | if (hw->phy.ops.read_reg(hw, IXGBE_PHY_OVERTEMP_STATUS, | ||||
IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, | IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, ®)) { | ||||
®)) { | |||||
device_printf(adapter->dev, | device_printf(adapter->dev, | ||||
"Error reading from PHY's temperature status register\n"); | "Error reading from PHY's temperature status register\n"); | ||||
return (EAGAIN); | return (EAGAIN); | ||||
} | } | ||||
/* Get occurrence bit */ | /* Get occurrence bit */ | ||||
reg = !!(reg & 0x4000); | reg = !!(reg & 0x4000); | ||||
return (sysctl_handle_int(oidp, 0, reg, req)); | return (sysctl_handle_int(oidp, 0, reg, req)); | ||||
} | } /* ixgbe_sysctl_phy_overtemp_occurred */ | ||||
/* | /************************************************************************ | ||||
** Thermal Shutdown Trigger (internal MAC) | * ixgbe_sysctl_thermal_test | ||||
** - Set this to 1 to cause an overtemp event to occur | * | ||||
*/ | * Thermal Shutdown Trigger (internal MAC) | ||||
* - Set this to 1 to cause an overtemp event to occur | |||||
************************************************************************/ | |||||
static int | static int | ||||
ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_thermal_test(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *adapter = (struct adapter *) arg1; | struct adapter *adapter = (struct adapter *) arg1; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
int error, fire = 0; | int error, fire = 0; | ||||
error = sysctl_handle_int(oidp, &fire, 0, req); | error = sysctl_handle_int(oidp, &fire, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
if (fire) { | if (fire) { | ||||
u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS); | u32 reg = IXGBE_READ_REG(hw, IXGBE_EICS); | ||||
reg |= IXGBE_EICR_TS; | reg |= IXGBE_EICR_TS; | ||||
IXGBE_WRITE_REG(hw, IXGBE_EICS, reg); | IXGBE_WRITE_REG(hw, IXGBE_EICS, reg); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_sysctl_thermal_test */ | ||||
/* | /************************************************************************ | ||||
** Manage DMA Coalescing. | * ixgbe_sysctl_dmac - Manage DMA Coalescing | ||||
** Control values: | * | ||||
** 0/1 - off / on (use default value of 1000) | * Control values: | ||||
** | * 0/1 - off / on (use default value of 1000) | ||||
** Legal timer values are: | * | ||||
** 50,100,250,500,1000,2000,5000,10000 | * Legal timer values are: | ||||
** | * 50,100,250,500,1000,2000,5000,10000 | ||||
** Turning off interrupt moderation will also turn this off. | * | ||||
*/ | * Turning off interrupt moderation will also turn this off. | ||||
************************************************************************/ | |||||
static int | static int | ||||
ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_dmac(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *adapter = (struct adapter *) arg1; | struct adapter *adapter = (struct adapter *) arg1; | ||||
struct ifnet *ifp = adapter->ifp; | struct ifnet *ifp = adapter->ifp; | ||||
int error; | int error; | ||||
u32 newval; | u32 newval; | ||||
newval = adapter->dmac; | newval = adapter->dmac; | ||||
error = sysctl_handle_int(oidp, &newval, 0, req); | error = sysctl_handle_int(oidp, &newval, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
switch (newval) { | switch (newval) { | ||||
case 0: | case 0: | ||||
Show All 20 Lines | default: | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* Re-initialize hardware if it's already running */ | /* Re-initialize hardware if it's already running */ | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | if (ifp->if_drv_flags & IFF_DRV_RUNNING) | ||||
ixgbe_init(adapter); | ixgbe_init(adapter); | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_sysctl_dmac */ | ||||
#ifdef IXGBE_DEBUG | #ifdef IXGBE_DEBUG | ||||
/** | /************************************************************************ | ||||
* ixgbe_sysctl_power_state | |||||
* | |||||
* Sysctl to test power states | * Sysctl to test power states | ||||
* Values: | * Values: | ||||
* 0 - set device to D0 | * 0 - set device to D0 | ||||
* 3 - set device to D3 | * 3 - set device to D3 | ||||
* (none) - get current device power state | * (none) - get current device power state | ||||
*/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_power_state(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *adapter = (struct adapter *) arg1; | struct adapter *adapter = (struct adapter *) arg1; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
int curr_ps, new_ps, error = 0; | int curr_ps, new_ps, error = 0; | ||||
curr_ps = new_ps = pci_get_powerstate(dev); | curr_ps = new_ps = pci_get_powerstate(dev); | ||||
error = sysctl_handle_int(oidp, &new_ps, 0, req); | error = sysctl_handle_int(oidp, &new_ps, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
if (new_ps == curr_ps) | if (new_ps == curr_ps) | ||||
return (0); | return (0); | ||||
if (new_ps == 3 && curr_ps == 0) | if (new_ps == 3 && curr_ps == 0) | ||||
error = DEVICE_SUSPEND(dev); | error = DEVICE_SUSPEND(dev); | ||||
else if (new_ps == 0 && curr_ps == 3) | else if (new_ps == 0 && curr_ps == 3) | ||||
error = DEVICE_RESUME(dev); | error = DEVICE_RESUME(dev); | ||||
else | else | ||||
return (EINVAL); | return (EINVAL); | ||||
device_printf(dev, "New state: %d\n", pci_get_powerstate(dev)); | device_printf(dev, "New state: %d\n", pci_get_powerstate(dev)); | ||||
return (error); | return (error); | ||||
} | } /* ixgbe_sysctl_power_state */ | ||||
#endif | #endif | ||||
/* | |||||
* Sysctl to enable/disable the WoL capability, if supported by the adapter. | /************************************************************************ | ||||
* ixgbe_sysctl_wol_enable | |||||
* | |||||
* Sysctl to enable/disable the WoL capability, | |||||
* if supported by the adapter. | |||||
* | |||||
* Values: | * Values: | ||||
* 0 - disabled | * 0 - disabled | ||||
* 1 - enabled | * 1 - enabled | ||||
*/ | ************************************************************************/ | ||||
static int | static int | ||||
ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_wol_enable(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *adapter = (struct adapter *) arg1; | struct adapter *adapter = (struct adapter *) arg1; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
int new_wol_enabled; | int new_wol_enabled; | ||||
int error = 0; | int error = 0; | ||||
new_wol_enabled = hw->wol_enabled; | new_wol_enabled = hw->wol_enabled; | ||||
error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req); | error = sysctl_handle_int(oidp, &new_wol_enabled, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
new_wol_enabled = !!(new_wol_enabled); | new_wol_enabled = !!(new_wol_enabled); | ||||
if (new_wol_enabled == hw->wol_enabled) | if (new_wol_enabled == hw->wol_enabled) | ||||
return (0); | return (0); | ||||
if (new_wol_enabled > 0 && !adapter->wol_support) | if (new_wol_enabled > 0 && !adapter->wol_support) | ||||
return (ENODEV); | return (ENODEV); | ||||
else | else | ||||
hw->wol_enabled = new_wol_enabled; | hw->wol_enabled = new_wol_enabled; | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_sysctl_wol_enable */ | ||||
/* | /* | ||||
* Sysctl to enable/disable the Energy Efficient Ethernet capability, | * Sysctl to enable/disable the Energy Efficient Ethernet capability, | ||||
* if supported by the adapter. | * if supported by the adapter. | ||||
* Values: | * Values: | ||||
* 0 - disabled | * 0 - disabled | ||||
* 1 - enabled | * 1 - enabled | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | ixgbe_sysctl_eee_tx_lpi_delay(SYSCTL_HANDLER_ARGS) | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
u32 reg; | u32 reg; | ||||
reg = IXGBE_READ_REG(hw, IXGBE_EEE_SU); | reg = IXGBE_READ_REG(hw, IXGBE_EEE_SU); | ||||
return (sysctl_handle_int(oidp, 0, reg >> 26, req)); | return (sysctl_handle_int(oidp, 0, reg >> 26, req)); | ||||
} | } | ||||
/* | /************************************************************************ | ||||
* ixgbe_sysctl_wufc | |||||
* | |||||
* Sysctl to enable/disable the types of packets that the | * Sysctl to enable/disable the types of packets that the | ||||
* adapter will wake up on upon receipt. | * adapter will wake up on upon receipt. | ||||
* WUFC - Wake Up Filter Control | |||||
* Flags: | * Flags: | ||||
* 0x1 - Link Status Change | * 0x1 - Link Status Change | ||||
* 0x2 - Magic Packet | * 0x2 - Magic Packet | ||||
* 0x4 - Direct Exact | * 0x4 - Direct Exact | ||||
* 0x8 - Directed Multicast | * 0x8 - Directed Multicast | ||||
* 0x10 - Broadcast | * 0x10 - Broadcast | ||||
* 0x20 - ARP/IPv4 Request Packet | * 0x20 - ARP/IPv4 Request Packet | ||||
* 0x40 - Direct IPv4 Packet | * 0x40 - Direct IPv4 Packet | ||||
* 0x80 - Direct IPv6 Packet | * 0x80 - Direct IPv6 Packet | ||||
* | * | ||||
* Setting another flag will cause the sysctl to return an | * Settings not listed above will cause the sysctl to return an error. | ||||
* error. | ************************************************************************/ | ||||
*/ | |||||
static int | static int | ||||
ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_wufc(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *adapter = (struct adapter *) arg1; | struct adapter *adapter = (struct adapter *) arg1; | ||||
int error = 0; | int error = 0; | ||||
u32 new_wufc; | u32 new_wufc; | ||||
new_wufc = adapter->wufc; | new_wufc = adapter->wufc; | ||||
error = sysctl_handle_int(oidp, &new_wufc, 0, req); | error = sysctl_handle_int(oidp, &new_wufc, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
if (new_wufc == adapter->wufc) | if (new_wufc == adapter->wufc) | ||||
return (0); | return (0); | ||||
if (new_wufc & 0xffffff00) | if (new_wufc & 0xffffff00) | ||||
return (EINVAL); | return (EINVAL); | ||||
else { | else { | ||||
new_wufc &= 0xff; | new_wufc &= 0xff; | ||||
new_wufc |= (0xffffff & adapter->wufc); | new_wufc |= (0xffffff & adapter->wufc); | ||||
adapter->wufc = new_wufc; | adapter->wufc = new_wufc; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_sysctl_wufc */ | ||||
#ifdef IXGBE_DEBUG | #ifdef IXGBE_DEBUG | ||||
/************************************************************************ | |||||
* ixgbe_sysctl_print_rss_config | |||||
************************************************************************/ | |||||
static int | static int | ||||
ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS) | ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct adapter *adapter = (struct adapter *)arg1; | struct adapter *adapter = (struct adapter *)arg1; | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
device_t dev = adapter->dev; | device_t dev = adapter->dev; | ||||
int error = 0, reta_size; | |||||
struct sbuf *buf; | struct sbuf *buf; | ||||
int error = 0, reta_size; | |||||
u32 reg; | u32 reg; | ||||
buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); | buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); | ||||
if (!buf) { | if (!buf) { | ||||
device_printf(dev, "Could not allocate sbuf for output.\n"); | device_printf(dev, "Could not allocate sbuf for output.\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
// TODO: use sbufs to make a string to print out | // TODO: use sbufs to make a string to print out | ||||
Show All 22 Lines | ixgbe_sysctl_print_rss_config(SYSCTL_HANDLER_ARGS) | ||||
// TODO: print more config | // TODO: print more config | ||||
error = sbuf_finish(buf); | error = sbuf_finish(buf); | ||||
if (error) | if (error) | ||||
device_printf(dev, "Error finishing sbuf: %d\n", error); | device_printf(dev, "Error finishing sbuf: %d\n", error); | ||||
sbuf_delete(buf); | sbuf_delete(buf); | ||||
return (0); | return (0); | ||||
} | } /* ixgbe_sysctl_print_rss_config */ | ||||
#endif /* IXGBE_DEBUG */ | #endif /* IXGBE_DEBUG */ | ||||
/* | /************************************************************************ | ||||
** Enable the hardware to drop packets when the buffer is | * ixgbe_enable_rx_drop | ||||
** full. This is useful when multiqueue,so that no single | * | ||||
** queue being full stalls the entire RX engine. We only | * Enable the hardware to drop packets when the buffer is | ||||
** enable this when Multiqueue AND when Flow Control is | * full. This is useful with multiqueue, so that no single | ||||
** disabled. | * queue being full stalls the entire RX engine. We only | ||||
*/ | * enable this when Multiqueue is enabled AND Flow Control | ||||
* is disabled. | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_enable_rx_drop(struct adapter *adapter) | ixgbe_enable_rx_drop(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0; i < adapter->num_queues; i++) { | ||||
struct rx_ring *rxr = &adapter->rx_rings[i]; | struct rx_ring *rxr = &adapter->rx_rings[i]; | ||||
u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); | u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); | ||||
srrctl |= IXGBE_SRRCTL_DROP_EN; | srrctl |= IXGBE_SRRCTL_DROP_EN; | ||||
IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); | IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); | ||||
} | } | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
/* enable drop for each vf */ | /* enable drop for each vf */ | ||||
for (int i = 0; i < adapter->num_vfs; i++) { | for (int i = 0; i < adapter->num_vfs; i++) { | ||||
IXGBE_WRITE_REG(hw, IXGBE_QDE, | IXGBE_WRITE_REG(hw, IXGBE_QDE, | ||||
(IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) | | (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT) | | ||||
IXGBE_QDE_ENABLE)); | IXGBE_QDE_ENABLE)); | ||||
} | } | ||||
#endif | #endif | ||||
} | } /* ixgbe_enable_rx_drop */ | ||||
/************************************************************************ | |||||
* ixgbe_disable_rx_drop | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_disable_rx_drop(struct adapter *adapter) | ixgbe_disable_rx_drop(struct adapter *adapter) | ||||
{ | { | ||||
struct ixgbe_hw *hw = &adapter->hw; | struct ixgbe_hw *hw = &adapter->hw; | ||||
for (int i = 0; i < adapter->num_queues; i++) { | for (int i = 0; i < adapter->num_queues; i++) { | ||||
struct rx_ring *rxr = &adapter->rx_rings[i]; | struct rx_ring *rxr = &adapter->rx_rings[i]; | ||||
u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); | u32 srrctl = IXGBE_READ_REG(hw, IXGBE_SRRCTL(rxr->me)); | ||||
srrctl &= ~IXGBE_SRRCTL_DROP_EN; | srrctl &= ~IXGBE_SRRCTL_DROP_EN; | ||||
IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); | IXGBE_WRITE_REG(hw, IXGBE_SRRCTL(rxr->me), srrctl); | ||||
} | } | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
/* disable drop for each vf */ | /* disable drop for each vf */ | ||||
for (int i = 0; i < adapter->num_vfs; i++) { | for (int i = 0; i < adapter->num_vfs; i++) { | ||||
IXGBE_WRITE_REG(hw, IXGBE_QDE, | IXGBE_WRITE_REG(hw, IXGBE_QDE, | ||||
(IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT))); | (IXGBE_QDE_WRITE | (i << IXGBE_QDE_IDX_SHIFT))); | ||||
} | } | ||||
#endif | #endif | ||||
} | } /* ixgbe_disable_rx_drop */ | ||||
/************************************************************************ | |||||
* ixgbe_rearm_queues | |||||
************************************************************************/ | |||||
static void | static void | ||||
ixgbe_rearm_queues(struct adapter *adapter, u64 queues) | ixgbe_rearm_queues(struct adapter *adapter, u64 queues) | ||||
{ | { | ||||
u32 mask; | u32 mask; | ||||
switch (adapter->hw.mac.type) { | switch (adapter->hw.mac.type) { | ||||
case ixgbe_mac_82598EB: | case ixgbe_mac_82598EB: | ||||
mask = (IXGBE_EIMS_RTX_QUEUE & queues); | mask = (IXGBE_EIMS_RTX_QUEUE & queues); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask); | ||||
break; | break; | ||||
case ixgbe_mac_82599EB: | case ixgbe_mac_82599EB: | ||||
case ixgbe_mac_X540: | case ixgbe_mac_X540: | ||||
case ixgbe_mac_X550: | case ixgbe_mac_X550: | ||||
case ixgbe_mac_X550EM_x: | case ixgbe_mac_X550EM_x: | ||||
mask = (queues & 0xFFFFFFFF); | mask = (queues & 0xFFFFFFFF); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask); | ||||
mask = (queues >> 32); | mask = (queues >> 32); | ||||
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); | IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(1), mask); | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } /* ixgbe_rearm_queues */ | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
/* | /* | ||||
** Support functions for SRIOV/VF management | ** Support functions for SRIOV/VF management | ||||
*/ | */ | ||||
static void | static void | ||||
▲ Show 20 Lines • Show All 712 Lines • Show Last 20 Lines |