Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ice/ice_lib.c
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
#include "ice_lib.h" | #include "ice_lib.h" | ||||
#include "ice_iflib.h" | #include "ice_iflib.h" | ||||
#include <dev/pci/pcivar.h> | #include <dev/pci/pcivar.h> | ||||
#include <dev/pci/pcireg.h> | #include <dev/pci/pcireg.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <sys/firmware.h> | #include <sys/firmware.h> | ||||
#include <sys/priv.h> | #include <sys/priv.h> | ||||
#include <sys/limits.h> | |||||
/** | /** | ||||
* @var M_ICE | * @var M_ICE | ||||
* @brief main ice driver allocation type | * @brief main ice driver allocation type | ||||
* | * | ||||
* malloc(9) allocation type used by the majority of memory allocations in the | * malloc(9) allocation type used by the majority of memory allocations in the | ||||
* ice driver. | * ice driver. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
ice_handle_lan_overflow_event(struct ice_softc *sc, | ice_handle_lan_overflow_event(struct ice_softc *sc, | ||||
struct ice_rq_event_info *event); | struct ice_rq_event_info *event); | ||||
static int ice_add_ethertype_to_list(struct ice_vsi *vsi, | static int ice_add_ethertype_to_list(struct ice_vsi *vsi, | ||||
struct ice_list_head *list, | struct ice_list_head *list, | ||||
u16 ethertype, u16 direction, | u16 ethertype, u16 direction, | ||||
enum ice_sw_fwd_act_type action); | enum ice_sw_fwd_act_type action); | ||||
static void ice_add_rx_lldp_filter(struct ice_softc *sc); | static void ice_add_rx_lldp_filter(struct ice_softc *sc); | ||||
static void ice_del_rx_lldp_filter(struct ice_softc *sc); | static void ice_del_rx_lldp_filter(struct ice_softc *sc); | ||||
static u16 ice_aq_phy_types_to_sysctl_speeds(u64 phy_type_low, | static u16 ice_aq_phy_types_to_link_speeds(u64 phy_type_low, | ||||
u64 phy_type_high); | u64 phy_type_high); | ||||
static void | struct ice_phy_data; | ||||
ice_apply_saved_phy_req_to_cfg(struct ice_port_info *pi, | static int | ||||
struct ice_aqc_get_phy_caps_data *pcaps, | ice_intersect_phy_types_and_speeds(struct ice_softc *sc, | ||||
struct ice_phy_data *phy_data); | |||||
static int | |||||
ice_apply_saved_phy_req_to_cfg(struct ice_softc *sc, | |||||
struct ice_aqc_set_phy_cfg_data *cfg); | struct ice_aqc_set_phy_cfg_data *cfg); | ||||
static void | static int | ||||
ice_apply_saved_fec_req_to_cfg(struct ice_port_info *pi, | ice_apply_saved_fec_req_to_cfg(struct ice_softc *sc, | ||||
struct ice_aqc_get_phy_caps_data *pcaps, | |||||
struct ice_aqc_set_phy_cfg_data *cfg); | struct ice_aqc_set_phy_cfg_data *cfg); | ||||
static void | static void | ||||
ice_apply_saved_user_req_to_cfg(struct ice_port_info *pi, | |||||
struct ice_aqc_get_phy_caps_data *pcaps, | |||||
struct ice_aqc_set_phy_cfg_data *cfg); | |||||
static void | |||||
ice_apply_saved_fc_req_to_cfg(struct ice_port_info *pi, | ice_apply_saved_fc_req_to_cfg(struct ice_port_info *pi, | ||||
struct ice_aqc_set_phy_cfg_data *cfg); | struct ice_aqc_set_phy_cfg_data *cfg); | ||||
static void | static void | ||||
ice_print_ldo_tlv(struct ice_softc *sc, | ice_print_ldo_tlv(struct ice_softc *sc, | ||||
struct ice_link_default_override_tlv *tlv); | struct ice_link_default_override_tlv *tlv); | ||||
static void | static void | ||||
ice_sysctl_speeds_to_aq_phy_types(u16 sysctl_speeds, u64 *phy_type_low, | ice_sysctl_speeds_to_aq_phy_types(u16 sysctl_speeds, u64 *phy_type_low, | ||||
u64 *phy_type_high); | u64 *phy_type_high); | ||||
static int | static u16 ice_apply_supported_speed_filter(u16 report_speeds); | ||||
ice_intersect_media_types_with_caps(struct ice_softc *sc, u16 sysctl_speeds, | |||||
u64 *phy_type_low, u64 *phy_type_high); | |||||
static int | |||||
ice_get_auto_speeds(struct ice_softc *sc, u64 *phy_type_low, | |||||
u64 *phy_type_high); | |||||
static void | static void | ||||
ice_apply_supported_speed_filter(u64 *phy_type_low, u64 *phy_type_high); | ice_handle_health_status_event(struct ice_softc *sc, | ||||
static enum ice_status | struct ice_rq_event_info *event); | ||||
ice_get_phy_types(struct ice_softc *sc, u64 *phy_type_low, u64 *phy_type_high); | static void | ||||
ice_print_health_status_string(device_t dev, | |||||
struct ice_aqc_health_status_elem *elem); | |||||
static int ice_module_init(void); | static int ice_module_init(void); | ||||
static int ice_module_exit(void); | static int ice_module_exit(void); | ||||
/* | /* | ||||
* package version comparison functions | * package version comparison functions | ||||
*/ | */ | ||||
static bool pkg_ver_empty(struct ice_pkg_ver *pkg_ver, u8 *pkg_name); | static bool pkg_ver_empty(struct ice_pkg_ver *pkg_ver, u8 *pkg_name); | ||||
Show All 30 Lines | |||||
static int ice_sysctl_phy_sw_caps(SYSCTL_HANDLER_ARGS); | static int ice_sysctl_phy_sw_caps(SYSCTL_HANDLER_ARGS); | ||||
static int ice_sysctl_phy_nvm_caps(SYSCTL_HANDLER_ARGS); | static int ice_sysctl_phy_nvm_caps(SYSCTL_HANDLER_ARGS); | ||||
static int ice_sysctl_phy_topo_caps(SYSCTL_HANDLER_ARGS); | static int ice_sysctl_phy_topo_caps(SYSCTL_HANDLER_ARGS); | ||||
static int ice_sysctl_phy_link_status(SYSCTL_HANDLER_ARGS); | static int ice_sysctl_phy_link_status(SYSCTL_HANDLER_ARGS); | ||||
static int ice_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS); | static int ice_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS); | ||||
static int ice_sysctl_tx_cso_stat(SYSCTL_HANDLER_ARGS); | static int ice_sysctl_tx_cso_stat(SYSCTL_HANDLER_ARGS); | ||||
static int ice_sysctl_rx_cso_stat(SYSCTL_HANDLER_ARGS); | static int ice_sysctl_rx_cso_stat(SYSCTL_HANDLER_ARGS); | ||||
static int ice_sysctl_pba_number(SYSCTL_HANDLER_ARGS); | static int ice_sysctl_pba_number(SYSCTL_HANDLER_ARGS); | ||||
static int ice_sysctl_rx_errors_stat(SYSCTL_HANDLER_ARGS); | |||||
/** | /** | ||||
* ice_map_bar - Map PCIe BAR memory | * ice_map_bar - Map PCIe BAR memory | ||||
* @dev: the PCIe device | * @dev: the PCIe device | ||||
* @bar: the BAR info structure | * @bar: the BAR info structure | ||||
* @bar_num: PCIe BAR number | * @bar_num: PCIe BAR number | ||||
* | * | ||||
* Maps the specified PCIe BAR. Stores the mapping data in struct | * Maps the specified PCIe BAR. Stores the mapping data in struct | ||||
▲ Show 20 Lines • Show All 251 Lines • ▼ Show 20 Lines | ice_set_default_vsi_ctx(struct ice_vsi_ctx *ctx) | ||||
memset(&ctx->info, 0, sizeof(ctx->info)); | memset(&ctx->info, 0, sizeof(ctx->info)); | ||||
/* VSI will be allocated from shared pool */ | /* VSI will be allocated from shared pool */ | ||||
ctx->alloc_from_pool = true; | ctx->alloc_from_pool = true; | ||||
/* Enable source pruning by default */ | /* Enable source pruning by default */ | ||||
ctx->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE; | ctx->info.sw_flags = ICE_AQ_VSI_SW_FLAG_SRC_PRUNE; | ||||
/* Traffic from VSI can be sent to LAN */ | /* Traffic from VSI can be sent to LAN */ | ||||
ctx->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA; | ctx->info.sw_flags2 = ICE_AQ_VSI_SW_FLAG_LAN_ENA; | ||||
/* Allow all packets untagged/tagged */ | /* Allow all packets untagged/tagged */ | ||||
ctx->info.vlan_flags = ((ICE_AQ_VSI_VLAN_MODE_ALL & | ctx->info.inner_vlan_flags = ((ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL & | ||||
ICE_AQ_VSI_VLAN_MODE_M) >> | ICE_AQ_VSI_INNER_VLAN_TX_MODE_M) >> | ||||
ICE_AQ_VSI_VLAN_MODE_S); | ICE_AQ_VSI_INNER_VLAN_TX_MODE_S); | ||||
/* Show VLAN/UP from packets in Rx descriptors */ | /* Show VLAN/UP from packets in Rx descriptors */ | ||||
ctx->info.vlan_flags |= ((ICE_AQ_VSI_VLAN_EMOD_STR_BOTH & | ctx->info.inner_vlan_flags |= ((ICE_AQ_VSI_INNER_VLAN_EMODE_STR_BOTH & | ||||
ICE_AQ_VSI_VLAN_EMOD_M) >> | ICE_AQ_VSI_INNER_VLAN_EMODE_M) >> | ||||
ICE_AQ_VSI_VLAN_EMOD_S); | ICE_AQ_VSI_INNER_VLAN_EMODE_S); | ||||
/* Have 1:1 UP mapping for both ingress/egress tables */ | /* Have 1:1 UP mapping for both ingress/egress tables */ | ||||
table |= ICE_UP_TABLE_TRANSLATE(0, 0); | table |= ICE_UP_TABLE_TRANSLATE(0, 0); | ||||
table |= ICE_UP_TABLE_TRANSLATE(1, 1); | table |= ICE_UP_TABLE_TRANSLATE(1, 1); | ||||
table |= ICE_UP_TABLE_TRANSLATE(2, 2); | table |= ICE_UP_TABLE_TRANSLATE(2, 2); | ||||
table |= ICE_UP_TABLE_TRANSLATE(3, 3); | table |= ICE_UP_TABLE_TRANSLATE(3, 3); | ||||
table |= ICE_UP_TABLE_TRANSLATE(4, 4); | table |= ICE_UP_TABLE_TRANSLATE(4, 4); | ||||
table |= ICE_UP_TABLE_TRANSLATE(5, 5); | table |= ICE_UP_TABLE_TRANSLATE(5, 5); | ||||
table |= ICE_UP_TABLE_TRANSLATE(6, 6); | table |= ICE_UP_TABLE_TRANSLATE(6, 6); | ||||
table |= ICE_UP_TABLE_TRANSLATE(7, 7); | table |= ICE_UP_TABLE_TRANSLATE(7, 7); | ||||
ctx->info.ingress_table = CPU_TO_LE32(table); | ctx->info.ingress_table = CPU_TO_LE32(table); | ||||
ctx->info.egress_table = CPU_TO_LE32(table); | ctx->info.egress_table = CPU_TO_LE32(table); | ||||
/* Have 1:1 UP mapping for outer to inner UP table */ | /* Have 1:1 UP mapping for outer to inner UP table */ | ||||
ctx->info.outer_up_table = CPU_TO_LE32(table); | ctx->info.outer_up_table = CPU_TO_LE32(table); | ||||
/* No Outer tag support, so outer_tag_flags remains zero */ | /* No Outer tag support, so outer_vlan_flags remains zero */ | ||||
} | } | ||||
/** | /** | ||||
* ice_set_rss_vsi_ctx - Setup VSI context parameters for RSS | * ice_set_rss_vsi_ctx - Setup VSI context parameters for RSS | ||||
* @ctx: the VSI context to configure | * @ctx: the VSI context to configure | ||||
* @type: the VSI type | * @type: the VSI type | ||||
* | * | ||||
* Configures the VSI context for RSS, based on the VSI type. | * Configures the VSI context for RSS, based on the VSI type. | ||||
▲ Show 20 Lines • Show All 457 Lines • ▼ Show 20 Lines | default: | ||||
return IFM_UNKNOWN; | return IFM_UNKNOWN; | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* ice_phy_types_to_max_rate - Returns port's max supported baudrate | * ice_phy_types_to_max_rate - Returns port's max supported baudrate | ||||
* @pi: port info struct | * @pi: port info struct | ||||
* | * | ||||
* ice_aq_get_phy_caps() w/ ICE_AQC_REPORT_TOPO_CAP parameter needs to have | * ice_aq_get_phy_caps() w/ ICE_AQC_REPORT_TOPO_CAP_MEDIA parameter needs | ||||
* been called before this function for it to work. | * to have been called before this function for it to work. | ||||
*/ | */ | ||||
static uint64_t | static uint64_t | ||||
ice_phy_types_to_max_rate(struct ice_port_info *pi) | ice_phy_types_to_max_rate(struct ice_port_info *pi) | ||||
{ | { | ||||
uint64_t phy_low = pi->phy.phy_type_low; | uint64_t phy_low = pi->phy.phy_type_low; | ||||
uint64_t phy_high = pi->phy.phy_type_high; | uint64_t phy_high = pi->phy.phy_type_high; | ||||
uint64_t max_rate = 0; | uint64_t max_rate = 0; | ||||
int bit; | int bit; | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | |||||
* available. | * available. | ||||
* | * | ||||
* @pre this function must be protected from being called while another thread | * @pre this function must be protected from being called while another thread | ||||
* is accessing the ifmedia types. | * is accessing the ifmedia types. | ||||
*/ | */ | ||||
enum ice_status | enum ice_status | ||||
ice_add_media_types(struct ice_softc *sc, struct ifmedia *media) | ice_add_media_types(struct ice_softc *sc, struct ifmedia *media) | ||||
{ | { | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | |||||
struct ice_port_info *pi = sc->hw.port_info; | |||||
enum ice_status status; | enum ice_status status; | ||||
uint64_t phy_low, phy_high; | uint64_t phy_low, phy_high; | ||||
int bit; | int bit; | ||||
ASSERT_CFG_LOCKED(sc); | ASSERT_CFG_LOCKED(sc); | ||||
/* the maximum possible media type index is 511. We probably don't | /* the maximum possible media type index is 511. We probably don't | ||||
* need most of this space, but this ensures future compatibility when | * need most of this space, but this ensures future compatibility when | ||||
* additional media types are used. | * additional media types are used. | ||||
*/ | */ | ||||
ice_declare_bitmap(already_added, 511); | ice_declare_bitmap(already_added, 511); | ||||
/* Remove all previous media types */ | /* Remove all previous media types */ | ||||
ifmedia_removeall(media); | ifmedia_removeall(media); | ||||
status = ice_get_phy_types(sc, &phy_low, &phy_high); | status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, | ||||
&pcaps, NULL); | |||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
/* Function already prints appropriate error | device_printf(sc->dev, | ||||
* message | "%s: ice_aq_get_phy_caps (ACTIVE) failed; status %s, aq_err %s\n", | ||||
*/ | __func__, ice_status_str(status), | ||||
ice_aq_str(sc->hw.adminq.sq_last_status)); | |||||
return (status); | return (status); | ||||
} | } | ||||
phy_low = le64toh(pcaps.phy_type_low); | |||||
phy_high = le64toh(pcaps.phy_type_high); | |||||
/* make sure the added bitmap is zero'd */ | /* make sure the added bitmap is zero'd */ | ||||
memset(already_added, 0, sizeof(already_added)); | memset(already_added, 0, sizeof(already_added)); | ||||
/* coverity[address_of] */ | /* coverity[address_of] */ | ||||
for_each_set_bit(bit, &phy_low, 64) { | for_each_set_bit(bit, &phy_low, 64) { | ||||
uint64_t type = BIT_ULL(bit); | uint64_t type = BIT_ULL(bit); | ||||
int ostype; | int ostype; | ||||
▲ Show 20 Lines • Show All 811 Lines • ▼ Show 20 Lines | ice_process_link_event(struct ice_softc *sc, | ||||
if (pi->phy.link_info.topo_media_conflict & | if (pi->phy.link_info.topo_media_conflict & | ||||
(ICE_AQ_LINK_TOPO_CONFLICT | ICE_AQ_LINK_MEDIA_CONFLICT | | (ICE_AQ_LINK_TOPO_CONFLICT | ICE_AQ_LINK_MEDIA_CONFLICT | | ||||
ICE_AQ_LINK_TOPO_CORRUPT)) | ICE_AQ_LINK_TOPO_CORRUPT)) | ||||
device_printf(dev, | device_printf(dev, | ||||
"Possible mis-configuration of the Ethernet port detected; please use the Intel (R) Ethernet Port Configuration Tool utility to address the issue.\n"); | "Possible mis-configuration of the Ethernet port detected; please use the Intel (R) Ethernet Port Configuration Tool utility to address the issue.\n"); | ||||
if ((pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) && | if ((pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) && | ||||
!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP) && | !(pi->phy.link_info.link_info & ICE_AQ_LINK_UP)) { | ||||
!(pi->phy.link_info.an_info & ICE_AQ_QUALIFIED_MODULE)) | if (!(pi->phy.link_info.an_info & ICE_AQ_QUALIFIED_MODULE)) | ||||
device_printf(dev, | device_printf(dev, | ||||
"Link is disabled on this device because an unsupported module type was detected! Refer to the Intel (R) Ethernet Adapters and Devices User Guide for a list of supported modules.\n"); | "Link is disabled on this device because an unsupported module type was detected! Refer to the Intel (R) Ethernet Adapters and Devices User Guide for a list of supported modules.\n"); | ||||
if (pi->phy.link_info.link_cfg_err & ICE_AQ_LINK_MODULE_POWER_UNSUPPORTED) | |||||
device_printf(dev, | |||||
"The module's power requirements exceed the device's power supply. Cannot start link.\n"); | |||||
if (pi->phy.link_info.link_cfg_err & ICE_AQ_LINK_INVAL_MAX_POWER_LIMIT) | |||||
device_printf(dev, | |||||
"The installed module is incompatible with the device's NVM image. Cannot start link.\n"); | |||||
} | |||||
if (!(pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE)) { | if (!(pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE)) { | ||||
if (!ice_testandset_state(&sc->state, ICE_STATE_NO_MEDIA)) { | if (!ice_testandset_state(&sc->state, ICE_STATE_NO_MEDIA)) { | ||||
status = ice_aq_set_link_restart_an(pi, false, NULL); | status = ice_aq_set_link_restart_an(pi, false, NULL); | ||||
if (status != ICE_SUCCESS) | if (status != ICE_SUCCESS) | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: ice_aq_set_link_restart_an: status %s, aq_err %s\n", | "%s: ice_aq_set_link_restart_an: status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
Show All 32 Lines | case ice_mbx_opc_send_msg_to_pf: | ||||
/* TODO: handle IOV event */ | /* TODO: handle IOV event */ | ||||
break; | break; | ||||
case ice_aqc_opc_lldp_set_mib_change: | case ice_aqc_opc_lldp_set_mib_change: | ||||
ice_handle_mib_change_event(sc, event); | ice_handle_mib_change_event(sc, event); | ||||
break; | break; | ||||
case ice_aqc_opc_event_lan_overflow: | case ice_aqc_opc_event_lan_overflow: | ||||
ice_handle_lan_overflow_event(sc, event); | ice_handle_lan_overflow_event(sc, event); | ||||
break; | break; | ||||
case ice_aqc_opc_get_health_status: | |||||
ice_handle_health_status_event(sc, event); | |||||
break; | |||||
default: | default: | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"%s Receive Queue unhandled event 0x%04x ignored\n", | "%s Receive Queue unhandled event 0x%04x ignored\n", | ||||
qname, opcode); | qname, opcode); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | ice_process_ctrlq(struct ice_softc *sc, enum ice_ctl_q q_type, u16 *pending) | ||||
do { | do { | ||||
status = ice_clean_rq_elem(hw, cq, &event, pending); | status = ice_clean_rq_elem(hw, cq, &event, pending); | ||||
if (status == ICE_ERR_AQ_NO_WORK) | if (status == ICE_ERR_AQ_NO_WORK) | ||||
break; | break; | ||||
if (status) { | if (status) { | ||||
if (q_type == ICE_CTL_Q_ADMIN) | if (q_type == ICE_CTL_Q_ADMIN) | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"%s Receive Queue event error %s aq_err %s\n", | "%s Receive Queue event error %s\n", | ||||
qname, ice_status_str(status), | qname, ice_status_str(status)); | ||||
ice_aq_str(cq->rq_last_status)); | |||||
else | else | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"%s Receive Queue event error %s cq_err %d\n", | "%s Receive Queue event error %s\n", | ||||
qname, ice_status_str(status), cq->rq_last_status); | qname, ice_status_str(status)); | ||||
free(event.msg_buf, M_ICE); | free(event.msg_buf, M_ICE); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
/* XXX should we separate this handler by controlq type? */ | /* XXX should we separate this handler by controlq type? */ | ||||
ice_process_ctrlq_event(sc, qname, &event); | ice_process_ctrlq_event(sc, qname, &event); | ||||
} while (*pending && (++loop < ICE_CTRLQ_WORK_LIMIT)); | } while (*pending && (++loop < ICE_CTRLQ_WORK_LIMIT)); | ||||
free(event.msg_buf, M_ICE); | free(event.msg_buf, M_ICE); | ||||
▲ Show 20 Lines • Show All 683 Lines • ▼ Show 20 Lines | |||||
#define ICE_PHYS_100GB_HIGH \ | #define ICE_PHYS_100GB_HIGH \ | ||||
(ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4 | \ | (ICE_PHY_TYPE_HIGH_100GBASE_KR2_PAM4 | \ | ||||
ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC | \ | ICE_PHY_TYPE_HIGH_100G_CAUI2_AOC_ACC | \ | ||||
ICE_PHY_TYPE_HIGH_100G_CAUI2 | \ | ICE_PHY_TYPE_HIGH_100G_CAUI2 | \ | ||||
ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC | \ | ICE_PHY_TYPE_HIGH_100G_AUI2_AOC_ACC | \ | ||||
ICE_PHY_TYPE_HIGH_100G_AUI2) | ICE_PHY_TYPE_HIGH_100G_AUI2) | ||||
/** | /** | ||||
* ice_aq_phy_types_to_sysctl_speeds - Convert the PHY Types to speeds | * ice_aq_phy_types_to_link_speeds - Convert the PHY Types to speeds | ||||
* @phy_type_low: lower 64-bit PHY Type bitmask | * @phy_type_low: lower 64-bit PHY Type bitmask | ||||
* @phy_type_high: upper 64-bit PHY Type bitmask | * @phy_type_high: upper 64-bit PHY Type bitmask | ||||
* | * | ||||
* Convert the PHY Type fields from Get PHY Abilities and Set PHY Config into | * Convert the PHY Type fields from Get PHY Abilities and Set PHY Config into | ||||
* link speed flags. If phy_type_high has an unknown PHY type, then the return | * link speed flags. If phy_type_high has an unknown PHY type, then the return | ||||
* value will include the "ICE_AQ_LINK_SPEED_UNKNOWN" flag as well. | * value will include the "ICE_AQ_LINK_SPEED_UNKNOWN" flag as well. | ||||
*/ | */ | ||||
static u16 | static u16 | ||||
ice_aq_phy_types_to_sysctl_speeds(u64 phy_type_low, u64 phy_type_high) | ice_aq_phy_types_to_link_speeds(u64 phy_type_low, u64 phy_type_high) | ||||
{ | { | ||||
u16 sysctl_speeds = 0; | u16 sysctl_speeds = 0; | ||||
int bit; | int bit; | ||||
/* coverity[address_of] */ | /* coverity[address_of] */ | ||||
for_each_set_bit(bit, &phy_type_low, 64) | for_each_set_bit(bit, &phy_type_low, 64) | ||||
sysctl_speeds |= phy_link_speeds[bit]; | sysctl_speeds |= phy_link_speeds[bit]; | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (sysctl_speeds & ICE_AQ_LINK_SPEED_50GB) | ||||
*phy_type_low |= ICE_PHYS_50GB; | *phy_type_low |= ICE_PHYS_50GB; | ||||
if (sysctl_speeds & ICE_AQ_LINK_SPEED_100GB) { | if (sysctl_speeds & ICE_AQ_LINK_SPEED_100GB) { | ||||
*phy_type_low |= ICE_PHYS_100GB_LOW; | *phy_type_low |= ICE_PHYS_100GB_LOW; | ||||
*phy_type_high |= ICE_PHYS_100GB_HIGH; | *phy_type_high |= ICE_PHYS_100GB_HIGH; | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* ice_intersect_media_types_with_caps - Restrict input AQ PHY flags | * @struct ice_phy_data | ||||
* @sc: driver private structure | * @brief PHY caps and link speeds | ||||
* @sysctl_speeds: current SW configuration of PHY types | |||||
* @phy_type_low: input/output flag set for low PHY types | |||||
* @phy_type_high: input/output flag set for high PHY types | |||||
* | * | ||||
* Intersects the input PHY flags with PHY flags retrieved from the adapter to | * Buffer providing report mode and user speeds; | ||||
* ensure the flags are compatible. | * returning intersection of PHY types and speeds. | ||||
*/ | |||||
struct ice_phy_data { | |||||
u64 phy_low_orig; /* PHY low quad from report */ | |||||
u64 phy_high_orig; /* PHY high quad from report */ | |||||
u64 phy_low_intr; /* PHY low quad intersection with user speeds */ | |||||
u64 phy_high_intr; /* PHY high quad intersection with user speeds */ | |||||
u16 user_speeds_orig; /* Input from caller - See ICE_AQ_LINK_SPEED_* */ | |||||
u16 user_speeds_intr; /* Intersect with report speeds */ | |||||
u8 report_mode; /* See ICE_AQC_REPORT_* */ | |||||
}; | |||||
/** | |||||
* ice_intersect_phy_types_and_speeds - Return intersection of link speeds | |||||
* @sc: device private structure | |||||
* @phy_data: device PHY data | |||||
* | * | ||||
* @returns 0 on success, EIO if an AQ command fails, or EINVAL if input PHY | * On read: Displays the currently supported speeds | ||||
* types have no intersection with TOPO_CAPS and the adapter is in non-lenient | * On write: Sets the device's supported speeds | ||||
* mode | * Valid input flags: see ICE_SYSCTL_HELP_ADVERTISE_SPEED | ||||
*/ | */ | ||||
static int | static int | ||||
ice_intersect_media_types_with_caps(struct ice_softc *sc, u16 sysctl_speeds, | ice_intersect_phy_types_and_speeds(struct ice_softc *sc, | ||||
u64 *phy_type_low, u64 *phy_type_high) | struct ice_phy_data *phy_data) | ||||
{ | { | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | ||||
struct ice_port_info *pi = sc->hw.port_info; | const char *report_types[5] = { "w/o MEDIA", | ||||
device_t dev = sc->dev; | "w/MEDIA", | ||||
"ACTIVE", | |||||
"EDOOFUS", /* Not used */ | |||||
"DFLT" }; | |||||
struct ice_hw *hw = &sc->hw; | |||||
struct ice_port_info *pi = hw->port_info; | |||||
enum ice_status status; | enum ice_status status; | ||||
u64 temp_phy_low, temp_phy_high; | u16 report_speeds, temp_speeds; | ||||
u64 final_phy_low, final_phy_high; | u8 report_type; | ||||
u16 topo_speeds; | bool apply_speed_filter = false; | ||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP, | switch (phy_data->report_mode) { | ||||
&pcaps, NULL); | case ICE_AQC_REPORT_TOPO_CAP_NO_MEDIA: | ||||
if (status != ICE_SUCCESS) { | case ICE_AQC_REPORT_TOPO_CAP_MEDIA: | ||||
device_printf(dev, | case ICE_AQC_REPORT_ACTIVE_CFG: | ||||
"%s: ice_aq_get_phy_caps (TOPO_CAP) failed; status %s, aq_err %s\n", | case ICE_AQC_REPORT_DFLT_CFG: | ||||
__func__, ice_status_str(status), | report_type = phy_data->report_mode >> 1; | ||||
ice_aq_str(sc->hw.adminq.sq_last_status)); | break; | ||||
return (EIO); | default: | ||||
device_printf(sc->dev, | |||||
"%s: phy_data.report_mode \"%u\" doesn't exist\n", | |||||
__func__, phy_data->report_mode); | |||||
return (EINVAL); | |||||
} | } | ||||
final_phy_low = le64toh(pcaps.phy_type_low); | /* 0 is treated as "Auto"; the driver will handle selecting the | ||||
final_phy_high = le64toh(pcaps.phy_type_high); | * correct speeds. Including, in some cases, applying an override | ||||
* if provided. | |||||
topo_speeds = ice_aq_phy_types_to_sysctl_speeds(final_phy_low, | |||||
final_phy_high); | |||||
/* | |||||
* If the user specifies a subset of speeds the media is already | |||||
* capable of supporting, then we're good to go. | |||||
*/ | */ | ||||
if ((sysctl_speeds & topo_speeds) == sysctl_speeds) | if (phy_data->user_speeds_orig == 0) | ||||
goto intersect_final; | phy_data->user_speeds_orig = USHRT_MAX; | ||||
else if (ice_is_bit_set(sc->feat_en, ICE_FEATURE_LENIENT_LINK_MODE)) | |||||
apply_speed_filter = true; | |||||
temp_phy_low = final_phy_low; | status = ice_aq_get_phy_caps(pi, false, phy_data->report_mode, &pcaps, NULL); | ||||
temp_phy_high = final_phy_high; | |||||
/* | |||||
* Otherwise, we'll have to use the superset if Lenient Mode is | |||||
* supported. | |||||
*/ | |||||
if (ice_is_bit_set(sc->feat_en, ICE_FEATURE_LENIENT_LINK_MODE)) { | |||||
/* | |||||
* Start with masks that _don't_ include the PHY types | |||||
* discovered by the TOPO_CAP. | |||||
*/ | |||||
ice_sysctl_speeds_to_aq_phy_types(topo_speeds, &final_phy_low, | |||||
&final_phy_high); | |||||
final_phy_low = ~final_phy_low; | |||||
final_phy_high = ~final_phy_high; | |||||
/* Get the PHY types the NVM says we can support */ | |||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_NVM_CAP, | |||||
&pcaps, NULL); | |||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
device_printf(dev, | device_printf(sc->dev, | ||||
"%s: ice_aq_get_phy_caps (NVM_CAP) failed; status %s, aq_err %s\n", | "%s: ice_aq_get_phy_caps (%s) failed; status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, report_types[report_type], | ||||
ice_status_str(status), | |||||
ice_aq_str(sc->hw.adminq.sq_last_status)); | ice_aq_str(sc->hw.adminq.sq_last_status)); | ||||
return (status); | return (EIO); | ||||
} | } | ||||
/* | phy_data->phy_low_orig = le64toh(pcaps.phy_type_low); | ||||
* Clear out the unsupported PHY types, including those | phy_data->phy_high_orig = le64toh(pcaps.phy_type_high); | ||||
* from TOPO_CAP. | report_speeds = ice_aq_phy_types_to_link_speeds(phy_data->phy_low_orig, | ||||
*/ | phy_data->phy_high_orig); | ||||
final_phy_low &= le64toh(pcaps.phy_type_low); | if (apply_speed_filter) { | ||||
final_phy_high &= le64toh(pcaps.phy_type_high); | temp_speeds = ice_apply_supported_speed_filter(report_speeds); | ||||
/* | if ((phy_data->user_speeds_orig & temp_speeds) == 0) { | ||||
* Include PHY types from TOPO_CAP (which may be a subset | device_printf(sc->dev, | ||||
* of the types the NVM specifies). | "User-specified speeds (\"0x%04X\") not supported\n", | ||||
*/ | phy_data->user_speeds_orig); | ||||
final_phy_low |= temp_phy_low; | |||||
final_phy_high |= temp_phy_high; | |||||
} | |||||
intersect_final: | |||||
if (ice_is_bit_set(sc->feat_en, ICE_FEATURE_LENIENT_LINK_MODE)) | |||||
ice_apply_supported_speed_filter(&final_phy_low, &final_phy_high); | |||||
ice_sysctl_speeds_to_aq_phy_types(sysctl_speeds, &temp_phy_low, | |||||
&temp_phy_high); | |||||
final_phy_low &= temp_phy_low; | |||||
final_phy_high &= temp_phy_high; | |||||
if (final_phy_low == 0 && final_phy_high == 0) { | |||||
device_printf(dev, | |||||
"The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n"); | |||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
report_speeds = temp_speeds; | |||||
/* Overwrite input phy_type values and return */ | |||||
*phy_type_low = final_phy_low; | |||||
*phy_type_high = final_phy_high; | |||||
return (0); | |||||
} | } | ||||
ice_sysctl_speeds_to_aq_phy_types(phy_data->user_speeds_orig, | |||||
&phy_data->phy_low_intr, &phy_data->phy_high_intr); | |||||
phy_data->user_speeds_intr = phy_data->user_speeds_orig & report_speeds; | |||||
phy_data->phy_low_intr &= phy_data->phy_low_orig; | |||||
phy_data->phy_high_intr &= phy_data->phy_high_orig; | |||||
/** | |||||
* ice_get_auto_speeds - Get PHY type flags for "auto" speed | |||||
* @sc: driver private structure | |||||
* @phy_type_low: output low PHY type flags | |||||
* @phy_type_high: output high PHY type flags | |||||
* | |||||
* Retrieves a suitable set of PHY type flags to use for an "auto" speed | |||||
* setting by either using the NVM default overrides for speed, or retrieving | |||||
* a default from the adapter using Get PHY capabilities in TOPO_CAPS mode. | |||||
* | |||||
* @returns 0 on success or EIO on AQ command failure | |||||
*/ | |||||
static int | |||||
ice_get_auto_speeds(struct ice_softc *sc, u64 *phy_type_low, | |||||
u64 *phy_type_high) | |||||
{ | |||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | |||||
struct ice_hw *hw = &sc->hw; | |||||
struct ice_port_info *pi = hw->port_info; | |||||
device_t dev = sc->dev; | |||||
enum ice_status status; | |||||
if (ice_is_bit_set(sc->feat_en, ICE_FEATURE_DEFAULT_OVERRIDE)) { | |||||
/* copy over speed settings from LDO TLV */ | |||||
*phy_type_low = CPU_TO_LE64(sc->ldo_tlv.phy_type_low); | |||||
*phy_type_high = CPU_TO_LE64(sc->ldo_tlv.phy_type_high); | |||||
} else { | |||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP, | |||||
&pcaps, NULL); | |||||
if (status != ICE_SUCCESS) { | |||||
device_printf(dev, | |||||
"%s: ice_aq_get_phy_caps (TOPO_CAP) failed; status %s, aq_err %s\n", | |||||
__func__, ice_status_str(status), | |||||
ice_aq_str(hw->adminq.sq_last_status)); | |||||
return (EIO); | |||||
} | |||||
*phy_type_low = le64toh(pcaps.phy_type_low); | |||||
*phy_type_high = le64toh(pcaps.phy_type_high); | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
/** | /** | ||||
* ice_sysctl_advertise_speed - Display/change link speeds supported by port | * ice_sysctl_advertise_speed - Display/change link speeds supported by port | ||||
* @oidp: sysctl oid structure | * @oidp: sysctl oid structure | ||||
* @arg1: pointer to private data structure | * @arg1: pointer to private data structure | ||||
* @arg2: unused | * @arg2: unused | ||||
* @req: sysctl request pointer | * @req: sysctl request pointer | ||||
* | * | ||||
* On read: Displays the currently supported speeds | * On read: Displays the currently supported speeds | ||||
* On write: Sets the device's supported speeds | * On write: Sets the device's supported speeds | ||||
* Valid input flags: see ICE_SYSCTL_HELP_ADVERTISE_SPEED | * Valid input flags: see ICE_SYSCTL_HELP_ADVERTISE_SPEED | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_advertise_speed(SYSCTL_HANDLER_ARGS) | ice_sysctl_advertise_speed(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | struct ice_port_info *pi = sc->hw.port_info; | ||||
struct ice_aqc_set_phy_cfg_data cfg = { 0 }; | struct ice_phy_data phy_data = { 0 }; | ||||
struct ice_hw *hw = &sc->hw; | |||||
struct ice_port_info *pi = hw->port_info; | |||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
enum ice_status status; | u16 sysctl_speeds; | ||||
u64 phy_low, phy_high; | int ret; | ||||
u16 sysctl_speeds = 0; | |||||
int error = 0; | |||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
/* Get the current speeds from the adapter's "active" configuration. */ | /* Get the current speeds from the adapter's "active" configuration. */ | ||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG, | phy_data.report_mode = ICE_AQC_REPORT_ACTIVE_CFG; | ||||
&pcaps, NULL); | ret = ice_intersect_phy_types_and_speeds(sc, &phy_data); | ||||
if (status != ICE_SUCCESS) { | if (ret) { | ||||
device_printf(dev, | /* Error message already printed within function */ | ||||
"%s: ice_aq_get_phy_caps (SW_CFG) failed; status %s, aq_err %s\n", | return (ret); | ||||
__func__, ice_status_str(status), | |||||
ice_aq_str(hw->adminq.sq_last_status)); | |||||
return (EIO); | |||||
} | } | ||||
phy_low = le64toh(pcaps.phy_type_low); | sysctl_speeds = phy_data.user_speeds_intr; | ||||
phy_high = le64toh(pcaps.phy_type_high); | |||||
sysctl_speeds = ice_aq_phy_types_to_sysctl_speeds(phy_low, phy_high); | |||||
error = sysctl_handle_16(oidp, &sysctl_speeds, 0, req); | ret = sysctl_handle_16(oidp, &sysctl_speeds, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((ret) || (req->newptr == NULL)) | ||||
return (error); | return (ret); | ||||
if (sysctl_speeds > 0x7FF) { | if (sysctl_speeds > 0x7FF) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: \"%u\" is outside of the range of acceptable values.\n", | "%s: \"%u\" is outside of the range of acceptable values.\n", | ||||
__func__, sysctl_speeds); | __func__, sysctl_speeds); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* 0 is treated as "Auto"; the driver will handle selecting the correct speeds, | |||||
* or apply an override if one is specified in the NVM. | |||||
*/ | |||||
if (sysctl_speeds == 0) { | |||||
error = ice_get_auto_speeds(sc, &phy_low, &phy_high); | |||||
if (error) | |||||
/* Function already prints appropriate error message */ | |||||
return (error); | |||||
} else { | |||||
error = ice_intersect_media_types_with_caps(sc, sysctl_speeds, | |||||
&phy_low, &phy_high); | |||||
if (error) | |||||
/* Function already prints appropriate error message */ | |||||
return (error); | |||||
} | |||||
sysctl_speeds = ice_aq_phy_types_to_sysctl_speeds(phy_low, phy_high); | |||||
/* Cache new user setting for speeds */ | |||||
pi->phy.curr_user_speed_req = sysctl_speeds; | pi->phy.curr_user_speed_req = sysctl_speeds; | ||||
/* Setup new PHY config with new input PHY types */ | /* Apply settings requested by user */ | ||||
ice_copy_phy_caps_to_cfg(pi, &pcaps, &cfg); | return ice_apply_saved_phy_cfg(sc, ICE_APPLY_LS); | ||||
cfg.phy_type_low = phy_low; | |||||
cfg.phy_type_high = phy_high; | |||||
cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT | ICE_AQ_PHY_ENA_LINK; | |||||
status = ice_aq_set_phy_cfg(hw, pi, &cfg, NULL); | |||||
if (status != ICE_SUCCESS) { | |||||
/* Don't indicate failure if there's no media in the port -- the sysctl | |||||
* handler has saved the value and will apply it when media is inserted. | |||||
*/ | |||||
if (status == ICE_ERR_AQ_ERROR && | |||||
hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY) { | |||||
device_printf(dev, | |||||
"%s: Setting will be applied when media is inserted\n", __func__); | |||||
return (0); | |||||
} else { | |||||
device_printf(dev, | |||||
"%s: ice_aq_set_phy_cfg failed; status %s, aq_err %s\n", | |||||
__func__, ice_status_str(status), | |||||
ice_aq_str(hw->adminq.sq_last_status)); | |||||
return (EIO); | |||||
} | } | ||||
} | |||||
return (0); | |||||
} | |||||
#define ICE_SYSCTL_HELP_FEC_CONFIG \ | #define ICE_SYSCTL_HELP_FEC_CONFIG \ | ||||
"\nDisplay or set the port's requested FEC mode." \ | "\nDisplay or set the port's requested FEC mode." \ | ||||
"\n\tauto - " ICE_FEC_STRING_AUTO \ | "\n\tauto - " ICE_FEC_STRING_AUTO \ | ||||
"\n\tfc - " ICE_FEC_STRING_BASER \ | "\n\tfc - " ICE_FEC_STRING_BASER \ | ||||
"\n\trs - " ICE_FEC_STRING_RS \ | "\n\trs - " ICE_FEC_STRING_RS \ | ||||
"\n\tnone - " ICE_FEC_STRING_NONE \ | "\n\tnone - " ICE_FEC_STRING_NONE \ | ||||
"\nEither of the left or right strings above can be used to set the requested mode." | "\nEither of the left or right strings above can be used to set the requested mode." | ||||
/** | /** | ||||
* ice_sysctl_fec_config - Display/change the configured FEC mode | * ice_sysctl_fec_config - Display/change the configured FEC mode | ||||
* @oidp: sysctl oid structure | * @oidp: sysctl oid structure | ||||
* @arg1: pointer to private data structure | * @arg1: pointer to private data structure | ||||
* @arg2: unused | * @arg2: unused | ||||
* @req: sysctl request pointer | * @req: sysctl request pointer | ||||
* | * | ||||
* On read: Displays the configured FEC mode | * On read: Displays the configured FEC mode | ||||
* On write: Sets the device's FEC mode to the input string, if it's valid. | * On write: Sets the device's FEC mode to the input string, if it's valid. | ||||
* Valid input strings: see ICE_SYSCTL_HELP_FEC_CONFIG | * Valid input strings: see ICE_SYSCTL_HELP_FEC_CONFIG | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_fec_config(SYSCTL_HANDLER_ARGS) | ice_sysctl_fec_config(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
struct ice_port_info *pi = sc->hw.port_info; | struct ice_port_info *pi = sc->hw.port_info; | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | |||||
struct ice_aqc_set_phy_cfg_data cfg = { 0 }; | |||||
struct ice_hw *hw = &sc->hw; | |||||
enum ice_fec_mode new_mode; | enum ice_fec_mode new_mode; | ||||
enum ice_status status; | |||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
char req_fec[32]; | char req_fec[32]; | ||||
int error = 0; | int ret; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
bzero(req_fec, sizeof(req_fec)); | bzero(req_fec, sizeof(req_fec)); | ||||
strlcpy(req_fec, ice_requested_fec_mode(pi), sizeof(req_fec)); | strlcpy(req_fec, ice_requested_fec_mode(pi), sizeof(req_fec)); | ||||
error = sysctl_handle_string(oidp, req_fec, sizeof(req_fec), req); | ret = sysctl_handle_string(oidp, req_fec, sizeof(req_fec), req); | ||||
if ((error) || (req->newptr == NULL)) | if ((ret) || (req->newptr == NULL)) | ||||
return (error); | return (ret); | ||||
if (strcmp(req_fec, "auto") == 0 || | if (strcmp(req_fec, "auto") == 0 || | ||||
strcmp(req_fec, ice_fec_str(ICE_FEC_AUTO)) == 0) { | strcmp(req_fec, ice_fec_str(ICE_FEC_AUTO)) == 0) { | ||||
new_mode = ICE_FEC_AUTO; | new_mode = ICE_FEC_AUTO; | ||||
} else if (strcmp(req_fec, "fc") == 0 || | } else if (strcmp(req_fec, "fc") == 0 || | ||||
strcmp(req_fec, ice_fec_str(ICE_FEC_BASER)) == 0) { | strcmp(req_fec, ice_fec_str(ICE_FEC_BASER)) == 0) { | ||||
new_mode = ICE_FEC_BASER; | new_mode = ICE_FEC_BASER; | ||||
} else if (strcmp(req_fec, "rs") == 0 || | } else if (strcmp(req_fec, "rs") == 0 || | ||||
strcmp(req_fec, ice_fec_str(ICE_FEC_RS)) == 0) { | strcmp(req_fec, ice_fec_str(ICE_FEC_RS)) == 0) { | ||||
new_mode = ICE_FEC_RS; | new_mode = ICE_FEC_RS; | ||||
} else if (strcmp(req_fec, "none") == 0 || | } else if (strcmp(req_fec, "none") == 0 || | ||||
strcmp(req_fec, ice_fec_str(ICE_FEC_NONE)) == 0) { | strcmp(req_fec, ice_fec_str(ICE_FEC_NONE)) == 0) { | ||||
new_mode = ICE_FEC_NONE; | new_mode = ICE_FEC_NONE; | ||||
} else { | } else { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: \"%s\" is not a valid FEC mode\n", | "%s: \"%s\" is not a valid FEC mode\n", | ||||
__func__, req_fec); | __func__, req_fec); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* Cache user FEC mode for later link ups */ | /* Cache user FEC mode for later link ups */ | ||||
pi->phy.curr_user_fec_req = new_mode; | pi->phy.curr_user_fec_req = new_mode; | ||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG, | /* Apply settings requested by user */ | ||||
&pcaps, NULL); | return ice_apply_saved_phy_cfg(sc, ICE_APPLY_FEC); | ||||
if (status != ICE_SUCCESS) { | |||||
device_printf(dev, | |||||
"%s: ice_aq_get_phy_caps failed (SW_CFG); status %s, aq_err %s\n", | |||||
__func__, ice_status_str(status), | |||||
ice_aq_str(hw->adminq.sq_last_status)); | |||||
return (EIO); | |||||
} | } | ||||
ice_copy_phy_caps_to_cfg(pi, &pcaps, &cfg); | |||||
/* Get link_fec_opt/AUTO_FEC mode from TOPO caps for base for new FEC mode */ | |||||
memset(&pcaps, 0, sizeof(pcaps)); | |||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP, | |||||
&pcaps, NULL); | |||||
if (status != ICE_SUCCESS) { | |||||
device_printf(dev, | |||||
"%s: ice_aq_get_phy_caps failed (TOPO_CAP); status %s, aq_err %s\n", | |||||
__func__, ice_status_str(status), | |||||
ice_aq_str(hw->adminq.sq_last_status)); | |||||
return (EIO); | |||||
} | |||||
/* Configure new FEC options using TOPO caps */ | |||||
cfg.link_fec_opt = pcaps.link_fec_options; | |||||
cfg.caps &= ~ICE_AQ_PHY_ENA_AUTO_FEC; | |||||
if (pcaps.caps & ICE_AQC_PHY_EN_AUTO_FEC) | |||||
cfg.caps |= ICE_AQ_PHY_ENA_AUTO_FEC; | |||||
if (ice_is_bit_set(sc->feat_en, ICE_FEATURE_DEFAULT_OVERRIDE) && | |||||
new_mode == ICE_FEC_AUTO) { | |||||
/* copy over FEC settings from LDO TLV */ | |||||
cfg.link_fec_opt = sc->ldo_tlv.fec_options; | |||||
} else { | |||||
ice_cfg_phy_fec(pi, &cfg, new_mode); | |||||
/* Check if the new mode is valid, and exit with an error if not */ | |||||
if (cfg.link_fec_opt && | |||||
!(cfg.link_fec_opt & pcaps.link_fec_options)) { | |||||
device_printf(dev, | |||||
"%s: The requested FEC mode, %s, is not supported by current media\n", | |||||
__func__, ice_fec_str(new_mode)); | |||||
return (ENOTSUP); | |||||
} | |||||
} | |||||
cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; | |||||
status = ice_aq_set_phy_cfg(hw, pi, &cfg, NULL); | |||||
if (status != ICE_SUCCESS) { | |||||
/* Don't indicate failure if there's no media in the port -- the sysctl | |||||
* handler has saved the value and will apply it when media is inserted. | |||||
*/ | |||||
if (status == ICE_ERR_AQ_ERROR && | |||||
hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY) { | |||||
device_printf(dev, | |||||
"%s: Setting will be applied when media is inserted\n", __func__); | |||||
return (0); | |||||
} else { | |||||
device_printf(dev, | |||||
"%s: ice_aq_set_phy_cfg failed; status %s, aq_err %s\n", | |||||
__func__, ice_status_str(status), | |||||
ice_aq_str(hw->adminq.sq_last_status)); | |||||
return (EIO); | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
/** | /** | ||||
* ice_sysctl_negotiated_fec - Display the negotiated FEC mode on the link | * ice_sysctl_negotiated_fec - Display the negotiated FEC mode on the link | ||||
* @oidp: sysctl oid structure | * @oidp: sysctl oid structure | ||||
* @arg1: pointer to private data structure | * @arg1: pointer to private data structure | ||||
* @arg2: unused | * @arg2: unused | ||||
* @req: sysctl request pointer | * @req: sysctl request pointer | ||||
* | * | ||||
* On read: Displays the negotiated FEC mode, in a string | * On read: Displays the negotiated FEC mode, in a string | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_negotiated_fec(SYSCTL_HANDLER_ARGS) | ice_sysctl_negotiated_fec(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
char neg_fec[32]; | char neg_fec[32]; | ||||
int error; | int ret; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
/* Copy const string into a buffer to drop const qualifier */ | /* Copy const string into a buffer to drop const qualifier */ | ||||
bzero(neg_fec, sizeof(neg_fec)); | bzero(neg_fec, sizeof(neg_fec)); | ||||
strlcpy(neg_fec, ice_negotiated_fec_mode(hw->port_info), sizeof(neg_fec)); | strlcpy(neg_fec, ice_negotiated_fec_mode(hw->port_info), sizeof(neg_fec)); | ||||
error = sysctl_handle_string(oidp, neg_fec, 0, req); | ret = sysctl_handle_string(oidp, neg_fec, 0, req); | ||||
if (req->newptr != NULL) | if (req->newptr != NULL) | ||||
return (EPERM); | return (EPERM); | ||||
return (error); | return (ret); | ||||
} | } | ||||
#define ICE_SYSCTL_HELP_FC_CONFIG \ | #define ICE_SYSCTL_HELP_FC_CONFIG \ | ||||
"\nDisplay or set the port's advertised flow control mode.\n" \ | "\nDisplay or set the port's advertised flow control mode.\n" \ | ||||
"\t0 - " ICE_FC_STRING_NONE \ | "\t0 - " ICE_FC_STRING_NONE \ | ||||
"\n\t1 - " ICE_FC_STRING_RX \ | "\n\t1 - " ICE_FC_STRING_RX \ | ||||
"\n\t2 - " ICE_FC_STRING_TX \ | "\n\t2 - " ICE_FC_STRING_TX \ | ||||
"\n\t3 - " ICE_FC_STRING_FULL \ | "\n\t3 - " ICE_FC_STRING_FULL \ | ||||
Show All 15 Lines | |||||
{ | { | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
struct ice_port_info *pi = sc->hw.port_info; | struct ice_port_info *pi = sc->hw.port_info; | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | ||||
enum ice_fc_mode old_mode, new_mode; | enum ice_fc_mode old_mode, new_mode; | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
enum ice_status status; | enum ice_status status; | ||||
int error = 0, fc_num; | int ret, fc_num; | ||||
bool mode_set = false; | bool mode_set = false; | ||||
struct sbuf buf; | struct sbuf buf; | ||||
char *fc_str_end; | char *fc_str_end; | ||||
char fc_str[32]; | char fc_str[32]; | ||||
u8 aq_failures; | |||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG, | status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, | ||||
&pcaps, NULL); | &pcaps, NULL); | ||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: ice_aq_get_phy_caps failed; status %s, aq_err %s\n", | "%s: ice_aq_get_phy_caps failed; status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
Show All 11 Lines | ice_sysctl_fc_config(SYSCTL_HANDLER_ARGS) | ||||
/* Create "old" string for output */ | /* Create "old" string for output */ | ||||
bzero(fc_str, sizeof(fc_str)); | bzero(fc_str, sizeof(fc_str)); | ||||
sbuf_new_for_sysctl(&buf, fc_str, sizeof(fc_str), req); | sbuf_new_for_sysctl(&buf, fc_str, sizeof(fc_str), req); | ||||
sbuf_printf(&buf, "%d<%s>", old_mode, ice_fc_str(old_mode)); | sbuf_printf(&buf, "%d<%s>", old_mode, ice_fc_str(old_mode)); | ||||
sbuf_finish(&buf); | sbuf_finish(&buf); | ||||
sbuf_delete(&buf); | sbuf_delete(&buf); | ||||
error = sysctl_handle_string(oidp, fc_str, sizeof(fc_str), req); | ret = sysctl_handle_string(oidp, fc_str, sizeof(fc_str), req); | ||||
if ((error) || (req->newptr == NULL)) | if ((ret) || (req->newptr == NULL)) | ||||
return (error); | return (ret); | ||||
/* Try to parse input as a string, first */ | /* Try to parse input as a string, first */ | ||||
if (strcasecmp(ice_fc_str(ICE_FC_FULL), fc_str) == 0) { | if (strcasecmp(ice_fc_str(ICE_FC_FULL), fc_str) == 0) { | ||||
new_mode = ICE_FC_FULL; | new_mode = ICE_FC_FULL; | ||||
mode_set = true; | mode_set = true; | ||||
} | } | ||||
else if (strcasecmp(ice_fc_str(ICE_FC_TX_PAUSE), fc_str) == 0) { | else if (strcasecmp(ice_fc_str(ICE_FC_TX_PAUSE), fc_str) == 0) { | ||||
new_mode = ICE_FC_TX_PAUSE; | new_mode = ICE_FC_TX_PAUSE; | ||||
Show All 32 Lines | if (!mode_set) { | ||||
default: | default: | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: \"%s\" is not a valid flow control mode\n", | "%s: \"%s\" is not a valid flow control mode\n", | ||||
__func__, fc_str); | __func__, fc_str); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
} | } | ||||
/* Finally, set the flow control mode in FW */ | /* Set the flow control mode in FW */ | ||||
hw->port_info->fc.req_mode = new_mode; | pi->phy.curr_user_fc_req = new_mode; | ||||
status = ice_set_fc(pi, &aq_failures, true); | |||||
if (status != ICE_SUCCESS) { | |||||
/* Don't indicate failure if there's no media in the port -- the sysctl | |||||
* handler has saved the value and will apply it when media is inserted. | |||||
*/ | |||||
if (aq_failures == ICE_SET_FC_AQ_FAIL_SET && | |||||
hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY) { | |||||
device_printf(dev, | |||||
"%s: Setting will be applied when media is inserted\n", __func__); | |||||
return (0); | |||||
} else { | |||||
device_printf(dev, | |||||
"%s: ice_set_fc AQ failure = %d\n", __func__, aq_failures); | |||||
return (EIO); | |||||
} | |||||
} | |||||
return (0); | /* Apply settings requested by user */ | ||||
return ice_apply_saved_phy_cfg(sc, ICE_APPLY_FC); | |||||
} | } | ||||
/** | /** | ||||
* ice_sysctl_negotiated_fc - Display currently negotiated FC mode | * ice_sysctl_negotiated_fc - Display currently negotiated FC mode | ||||
* @oidp: sysctl oid structure | * @oidp: sysctl oid structure | ||||
* @arg1: pointer to private data structure | * @arg1: pointer to private data structure | ||||
* @arg2: unused | * @arg2: unused | ||||
* @req: sysctl request pointer | * @req: sysctl request pointer | ||||
Show All 35 Lines | |||||
{ | { | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | ||||
struct ice_aqc_set_phy_cfg_data cfg = { 0 }; | struct ice_aqc_set_phy_cfg_data cfg = { 0 }; | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
enum ice_status status; | enum ice_status status; | ||||
uint64_t types; | uint64_t types; | ||||
int error = 0; | int ret; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
status = ice_aq_get_phy_caps(hw->port_info, false, ICE_AQC_REPORT_SW_CFG, | status = ice_aq_get_phy_caps(hw->port_info, false, ICE_AQC_REPORT_ACTIVE_CFG, | ||||
&pcaps, NULL); | &pcaps, NULL); | ||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: ice_aq_get_phy_caps failed; status %s, aq_err %s\n", | "%s: ice_aq_get_phy_caps failed; status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
if (is_phy_type_high) | if (is_phy_type_high) | ||||
types = pcaps.phy_type_high; | types = pcaps.phy_type_high; | ||||
else | else | ||||
types = pcaps.phy_type_low; | types = pcaps.phy_type_low; | ||||
error = sysctl_handle_64(oidp, &types, sizeof(types), req); | ret = sysctl_handle_64(oidp, &types, sizeof(types), req); | ||||
if ((error) || (req->newptr == NULL)) | if ((ret) || (req->newptr == NULL)) | ||||
return (error); | return (ret); | ||||
ice_copy_phy_caps_to_cfg(hw->port_info, &pcaps, &cfg); | ice_copy_phy_caps_to_cfg(hw->port_info, &pcaps, &cfg); | ||||
if (is_phy_type_high) | if (is_phy_type_high) | ||||
cfg.phy_type_high = types & hw->port_info->phy.phy_type_high; | cfg.phy_type_high = types & hw->port_info->phy.phy_type_high; | ||||
else | else | ||||
cfg.phy_type_low = types & hw->port_info->phy.phy_type_low; | cfg.phy_type_low = types & hw->port_info->phy.phy_type_low; | ||||
cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; | cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
ice_sysctl_phy_caps(SYSCTL_HANDLER_ARGS, u8 report_mode) | ice_sysctl_phy_caps(SYSCTL_HANDLER_ARGS, u8 report_mode) | ||||
{ | { | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
struct ice_port_info *pi = hw->port_info; | struct ice_port_info *pi = hw->port_info; | ||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
enum ice_status status; | enum ice_status status; | ||||
int error; | int ret; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
error = priv_check(curthread, PRIV_DRIVER); | ret = priv_check(curthread, PRIV_DRIVER); | ||||
if (error) | if (ret) | ||||
return (error); | return (ret); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
status = ice_aq_get_phy_caps(pi, true, report_mode, &pcaps, NULL); | status = ice_aq_get_phy_caps(pi, true, report_mode, &pcaps, NULL); | ||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: ice_aq_get_phy_caps failed; status %s, aq_err %s\n", | "%s: ice_aq_get_phy_caps failed; status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
error = sysctl_handle_opaque(oidp, &pcaps, sizeof(pcaps), req); | ret = sysctl_handle_opaque(oidp, &pcaps, sizeof(pcaps), req); | ||||
if (req->newptr != NULL) | if (req->newptr != NULL) | ||||
return (EPERM); | return (EPERM); | ||||
return (error); | return (ret); | ||||
} | } | ||||
/** | /** | ||||
* ice_sysctl_phy_sw_caps - Display response from Get PHY abililties | * ice_sysctl_phy_sw_caps - Display response from Get PHY abililties | ||||
* @oidp: sysctl oid structure | * @oidp: sysctl oid structure | ||||
* @arg1: pointer to private data structure | * @arg1: pointer to private data structure | ||||
* @arg2: unused | * @arg2: unused | ||||
* @req: sysctl request pointer | * @req: sysctl request pointer | ||||
* | * | ||||
* On read: Display the response from Get PHY abillities reporting the last | * On read: Display the response from Get PHY abillities reporting the last | ||||
* software configuration. | * software configuration. | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_phy_sw_caps(SYSCTL_HANDLER_ARGS) | ice_sysctl_phy_sw_caps(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
return ice_sysctl_phy_caps(oidp, arg1, arg2, req, | return ice_sysctl_phy_caps(oidp, arg1, arg2, req, | ||||
ICE_AQC_REPORT_SW_CFG); | ICE_AQC_REPORT_ACTIVE_CFG); | ||||
} | } | ||||
/** | /** | ||||
* ice_sysctl_phy_nvm_caps - Display response from Get PHY abililties | * ice_sysctl_phy_nvm_caps - Display response from Get PHY abililties | ||||
* @oidp: sysctl oid structure | * @oidp: sysctl oid structure | ||||
* @arg1: pointer to private data structure | * @arg1: pointer to private data structure | ||||
* @arg2: unused | * @arg2: unused | ||||
* @req: sysctl request pointer | * @req: sysctl request pointer | ||||
* | * | ||||
* On read: Display the response from Get PHY abillities reporting the NVM | * On read: Display the response from Get PHY abillities reporting the NVM | ||||
* configuration. | * configuration. | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_phy_nvm_caps(SYSCTL_HANDLER_ARGS) | ice_sysctl_phy_nvm_caps(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
return ice_sysctl_phy_caps(oidp, arg1, arg2, req, | return ice_sysctl_phy_caps(oidp, arg1, arg2, req, | ||||
ICE_AQC_REPORT_NVM_CAP); | ICE_AQC_REPORT_TOPO_CAP_NO_MEDIA); | ||||
} | } | ||||
/** | /** | ||||
* ice_sysctl_phy_topo_caps - Display response from Get PHY abililties | * ice_sysctl_phy_topo_caps - Display response from Get PHY abililties | ||||
* @oidp: sysctl oid structure | * @oidp: sysctl oid structure | ||||
* @arg1: pointer to private data structure | * @arg1: pointer to private data structure | ||||
* @arg2: unused | * @arg2: unused | ||||
* @req: sysctl request pointer | * @req: sysctl request pointer | ||||
* | * | ||||
* On read: Display the response from Get PHY abillities reporting the | * On read: Display the response from Get PHY abillities reporting the | ||||
* topology configuration. | * topology configuration. | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_phy_topo_caps(SYSCTL_HANDLER_ARGS) | ice_sysctl_phy_topo_caps(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
return ice_sysctl_phy_caps(oidp, arg1, arg2, req, | return ice_sysctl_phy_caps(oidp, arg1, arg2, req, | ||||
ICE_AQC_REPORT_TOPO_CAP); | ICE_AQC_REPORT_TOPO_CAP_MEDIA); | ||||
} | } | ||||
/** | /** | ||||
* ice_sysctl_phy_link_status - Display response from Get Link Status | * ice_sysctl_phy_link_status - Display response from Get Link Status | ||||
* @oidp: sysctl oid structure | * @oidp: sysctl oid structure | ||||
* @arg1: pointer to private data structure | * @arg1: pointer to private data structure | ||||
* @arg2: unused | * @arg2: unused | ||||
* @req: sysctl request pointer | * @req: sysctl request pointer | ||||
* | * | ||||
* On read: Display the response from firmware for the Get Link Status | * On read: Display the response from firmware for the Get Link Status | ||||
* request. | * request. | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_phy_link_status(SYSCTL_HANDLER_ARGS) | ice_sysctl_phy_link_status(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ice_aqc_get_link_status_data link_data = { 0 }; | struct ice_aqc_get_link_status_data link_data = { 0 }; | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
struct ice_port_info *pi = hw->port_info; | struct ice_port_info *pi = hw->port_info; | ||||
struct ice_aqc_get_link_status *resp; | struct ice_aqc_get_link_status *resp; | ||||
struct ice_aq_desc desc; | struct ice_aq_desc desc; | ||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
enum ice_status status; | enum ice_status status; | ||||
int error; | int ret; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
/* | /* | ||||
* Ensure that only contexts with driver privilege are allowed to | * Ensure that only contexts with driver privilege are allowed to | ||||
* access this information | * access this information | ||||
*/ | */ | ||||
error = priv_check(curthread, PRIV_DRIVER); | ret = priv_check(curthread, PRIV_DRIVER); | ||||
if (error) | if (ret) | ||||
return (error); | return (ret); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_status); | ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_link_status); | ||||
resp = &desc.params.get_link_status; | resp = &desc.params.get_link_status; | ||||
resp->lport_num = pi->lport; | resp->lport_num = pi->lport; | ||||
status = ice_aq_send_cmd(hw, &desc, &link_data, sizeof(link_data), NULL); | status = ice_aq_send_cmd(hw, &desc, &link_data, sizeof(link_data), NULL); | ||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: ice_aq_send_cmd failed; status %s, aq_err %s\n", | "%s: ice_aq_send_cmd failed; status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
error = sysctl_handle_opaque(oidp, &link_data, sizeof(link_data), req); | ret = sysctl_handle_opaque(oidp, &link_data, sizeof(link_data), req); | ||||
if (req->newptr != NULL) | if (req->newptr != NULL) | ||||
return (EPERM); | return (EPERM); | ||||
return (error); | return (ret); | ||||
} | } | ||||
/** | /** | ||||
* ice_sysctl_fw_cur_lldp_persist_status - Display current FW LLDP status | * ice_sysctl_fw_cur_lldp_persist_status - Display current FW LLDP status | ||||
* @oidp: sysctl oid structure | * @oidp: sysctl oid structure | ||||
* @arg1: pointer to private softc structure | * @arg1: pointer to private softc structure | ||||
* @arg2: unused | * @arg2: unused | ||||
* @req: sysctl request pointer | * @req: sysctl request pointer | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_fw_lldp_agent(SYSCTL_HANDLER_ARGS) | ice_sysctl_fw_lldp_agent(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
enum ice_status status; | enum ice_status status; | ||||
int error = 0; | int ret; | ||||
u32 old_state; | u32 old_state; | ||||
u8 fw_lldp_enabled; | u8 fw_lldp_enabled; | ||||
bool retried_start_lldp = false; | bool retried_start_lldp = false; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
Show All 16 Lines | if (status) { | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
} | } | ||||
if (old_state == 0) | if (old_state == 0) | ||||
fw_lldp_enabled = false; | fw_lldp_enabled = false; | ||||
else | else | ||||
fw_lldp_enabled = true; | fw_lldp_enabled = true; | ||||
error = sysctl_handle_bool(oidp, &fw_lldp_enabled, 0, req); | ret = sysctl_handle_bool(oidp, &fw_lldp_enabled, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((ret) || (req->newptr == NULL)) | ||||
return (error); | return (ret); | ||||
if (old_state == 0 && fw_lldp_enabled == false) | if (old_state == 0 && fw_lldp_enabled == false) | ||||
return (0); | return (0); | ||||
if (old_state != 0 && fw_lldp_enabled == true) | if (old_state != 0 && fw_lldp_enabled == true) | ||||
return (0); | return (0); | ||||
if (fw_lldp_enabled == false) { | if (fw_lldp_enabled == false) { | ||||
Show All 32 Lines | if (status) { | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
} | } | ||||
hw->port_info->qos_cfg.is_sw_lldp = false; | hw->port_info->qos_cfg.is_sw_lldp = false; | ||||
} | } | ||||
return (error); | return (ret); | ||||
} | } | ||||
/** | /** | ||||
* ice_add_device_sysctls - add device specific dynamic sysctls | * ice_add_device_sysctls - add device specific dynamic sysctls | ||||
* @sc: device private structure | * @sc: device private structure | ||||
* | * | ||||
* Add per-device dynamic sysctls which show device configuration or enable | * Add per-device dynamic sysctls which show device configuration or enable | ||||
* configuring device functionality. For tunable values which can be set prior | * configuring device functionality. For tunable values which can be set prior | ||||
▲ Show 20 Lines • Show All 276 Lines • ▼ Show 20 Lines | ice_sysctl_rx_cso_stat(SYSCTL_HANDLER_ARGS) | ||||
/* Sum the stat for each of the Rx queues */ | /* Sum the stat for each of the Rx queues */ | ||||
for (i = 0; i < vsi->num_rx_queues; i++) | for (i = 0; i < vsi->num_rx_queues; i++) | ||||
stat += vsi->rx_queues[i].stats.cso[type]; | stat += vsi->rx_queues[i].stats.cso[type]; | ||||
return sysctl_handle_64(oidp, NULL, stat, req); | return sysctl_handle_64(oidp, NULL, stat, req); | ||||
} | } | ||||
/** | /** | ||||
* ice_sysctl_rx_errors_stat - Display aggregate of Rx errors | |||||
* @oidp: sysctl oid structure | |||||
* @arg1: pointer to private data structure | |||||
* @arg2: unused | |||||
* @req: sysctl request pointer | |||||
* | |||||
* On read: Sums current values of Rx error statistics and | |||||
* displays it. | |||||
*/ | |||||
static int | |||||
ice_sysctl_rx_errors_stat(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ice_vsi *vsi = (struct ice_vsi *)arg1; | |||||
struct ice_hw_port_stats *hs = &vsi->sc->stats.cur; | |||||
u64 stat = 0; | |||||
int i, type; | |||||
UNREFERENCED_PARAMETER(arg2); | |||||
if (ice_driver_is_detaching(vsi->sc)) | |||||
return (ESHUTDOWN); | |||||
stat += hs->rx_undersize; | |||||
stat += hs->rx_fragments; | |||||
stat += hs->rx_oversize; | |||||
stat += hs->rx_jabber; | |||||
stat += hs->rx_len_errors; | |||||
stat += hs->crc_errors; | |||||
stat += hs->illegal_bytes; | |||||
/* Checksum error stats */ | |||||
for (i = 0; i < vsi->num_rx_queues; i++) | |||||
for (type = ICE_CSO_STAT_RX_IP4_ERR; | |||||
type < ICE_CSO_STAT_RX_COUNT; | |||||
type++) | |||||
stat += vsi->rx_queues[i].stats.cso[type]; | |||||
return sysctl_handle_64(oidp, NULL, stat, req); | |||||
} | |||||
/** | |||||
* @struct ice_rx_cso_stat_info | * @struct ice_rx_cso_stat_info | ||||
* @brief sysctl information for an Rx checksum offload statistic | * @brief sysctl information for an Rx checksum offload statistic | ||||
* | * | ||||
* Structure used to simplify the process of defining the checksum offload | * Structure used to simplify the process of defining the checksum offload | ||||
* statistics. | * statistics. | ||||
*/ | */ | ||||
struct ice_rx_cso_stat_info { | struct ice_rx_cso_stat_info { | ||||
enum ice_rx_cso_stat type; | enum ice_rx_cso_stat type; | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | ice_add_vsi_sysctls(struct ice_vsi *vsi) | ||||
/* Add the ethernet statistics for this VSI */ | /* Add the ethernet statistics for this VSI */ | ||||
ice_add_sysctls_eth_stats(ctx, hw_node, &vsi->hw_stats.cur); | ice_add_sysctls_eth_stats(ctx, hw_node, &vsi->hw_stats.cur); | ||||
SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "rx_discards", | SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "rx_discards", | ||||
CTLFLAG_RD | CTLFLAG_STATS, &vsi->hw_stats.cur.rx_discards, | CTLFLAG_RD | CTLFLAG_STATS, &vsi->hw_stats.cur.rx_discards, | ||||
0, "Discarded Rx Packets (see rx_errors or rx_no_desc)"); | 0, "Discarded Rx Packets (see rx_errors or rx_no_desc)"); | ||||
SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "rx_errors", | SYSCTL_ADD_PROC(ctx, hw_list, OID_AUTO, "rx_errors", | ||||
CTLFLAG_RD | CTLFLAG_STATS, &vsi->hw_stats.cur.rx_errors, | CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_STATS, | ||||
0, "Rx Packets Discarded Due To Error"); | vsi, 0, ice_sysctl_rx_errors_stat, "QU", | ||||
"Aggregate of all Rx errors"); | |||||
SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "rx_no_desc", | SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "rx_no_desc", | ||||
CTLFLAG_RD | CTLFLAG_STATS, &vsi->hw_stats.cur.rx_no_desc, | CTLFLAG_RD | CTLFLAG_STATS, &vsi->hw_stats.cur.rx_no_desc, | ||||
0, "Rx Packets Discarded Due To Lack Of Descriptors"); | 0, "Rx Packets Discarded Due To Lack Of Descriptors"); | ||||
SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "tx_errors", | SYSCTL_ADD_U64(ctx, hw_list, OID_AUTO, "tx_errors", | ||||
CTLFLAG_RD | CTLFLAG_STATS, &vsi->hw_stats.cur.tx_errors, | CTLFLAG_RD | CTLFLAG_STATS, &vsi->hw_stats.cur.tx_errors, | ||||
0, "Tx Packets Discarded Due To Error"); | 0, "Tx Packets Discarded Due To Error"); | ||||
▲ Show 20 Lines • Show All 414 Lines • ▼ Show 20 Lines | |||||
* On read: Displays the current Rx ITR value | * On read: Displays the current Rx ITR value | ||||
* on write: Sets the Rx ITR value, reconfiguring device if it is up | * on write: Sets the Rx ITR value, reconfiguring device if it is up | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_rx_itr(SYSCTL_HANDLER_ARGS) | ice_sysctl_rx_itr(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ice_vsi *vsi = (struct ice_vsi *)arg1; | struct ice_vsi *vsi = (struct ice_vsi *)arg1; | ||||
struct ice_softc *sc = vsi->sc; | struct ice_softc *sc = vsi->sc; | ||||
int increment, error = 0; | int increment, ret; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
error = sysctl_handle_16(oidp, &vsi->rx_itr, 0, req); | ret = sysctl_handle_16(oidp, &vsi->rx_itr, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((ret) || (req->newptr == NULL)) | ||||
return (error); | return (ret); | ||||
if (vsi->rx_itr < 0) | if (vsi->rx_itr < 0) | ||||
vsi->rx_itr = ICE_DFLT_RX_ITR; | vsi->rx_itr = ICE_DFLT_RX_ITR; | ||||
if (vsi->rx_itr > ICE_ITR_MAX) | if (vsi->rx_itr > ICE_ITR_MAX) | ||||
vsi->rx_itr = ICE_ITR_MAX; | vsi->rx_itr = ICE_ITR_MAX; | ||||
/* Assume 2usec increment if it hasn't been loaded yet */ | /* Assume 2usec increment if it hasn't been loaded yet */ | ||||
increment = sc->hw.itr_gran ? : 2; | increment = sc->hw.itr_gran ? : 2; | ||||
Show All 26 Lines | |||||
* On read: Displays the current Tx ITR value | * On read: Displays the current Tx ITR value | ||||
* on write: Sets the Tx ITR value, reconfiguring device if it is up | * on write: Sets the Tx ITR value, reconfiguring device if it is up | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_tx_itr(SYSCTL_HANDLER_ARGS) | ice_sysctl_tx_itr(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ice_vsi *vsi = (struct ice_vsi *)arg1; | struct ice_vsi *vsi = (struct ice_vsi *)arg1; | ||||
struct ice_softc *sc = vsi->sc; | struct ice_softc *sc = vsi->sc; | ||||
int increment, error = 0; | int increment, ret; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
error = sysctl_handle_16(oidp, &vsi->tx_itr, 0, req); | ret = sysctl_handle_16(oidp, &vsi->tx_itr, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((ret) || (req->newptr == NULL)) | ||||
return (error); | return (ret); | ||||
/* Allow configuring a negative value to reset to the default */ | /* Allow configuring a negative value to reset to the default */ | ||||
if (vsi->tx_itr < 0) | if (vsi->tx_itr < 0) | ||||
vsi->tx_itr = ICE_DFLT_TX_ITR; | vsi->tx_itr = ICE_DFLT_TX_ITR; | ||||
if (vsi->tx_itr > ICE_ITR_MAX) | if (vsi->tx_itr > ICE_ITR_MAX) | ||||
vsi->tx_itr = ICE_ITR_MAX; | vsi->tx_itr = ICE_ITR_MAX; | ||||
/* Assume 2usec increment if it hasn't been loaded yet */ | /* Assume 2usec increment if it hasn't been loaded yet */ | ||||
▲ Show 20 Lines • Show All 530 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
ice_sysctl_request_reset(SYSCTL_HANDLER_ARGS) | ice_sysctl_request_reset(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
enum ice_status status; | enum ice_status status; | ||||
enum ice_reset_req reset_type = ICE_RESET_INVAL; | enum ice_reset_req reset_type = ICE_RESET_INVAL; | ||||
const char *reset_message; | const char *reset_message; | ||||
int error = 0; | int ret; | ||||
/* Buffer to store the requested reset string. Must contain enough | /* Buffer to store the requested reset string. Must contain enough | ||||
* space to store the largest expected reset string, which currently | * space to store the largest expected reset string, which currently | ||||
* means 6 bytes of space. | * means 6 bytes of space. | ||||
*/ | */ | ||||
char reset[6] = ""; | char reset[6] = ""; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
error = priv_check(curthread, PRIV_DRIVER); | ret = priv_check(curthread, PRIV_DRIVER); | ||||
if (error) | if (ret) | ||||
return (error); | return (ret); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
/* Read in the requested reset type. */ | /* Read in the requested reset type. */ | ||||
error = sysctl_handle_string(oidp, reset, sizeof(reset), req); | ret = sysctl_handle_string(oidp, reset, sizeof(reset), req); | ||||
if ((error) || (req->newptr == NULL)) | if ((ret) || (req->newptr == NULL)) | ||||
return (error); | return (ret); | ||||
if (strcmp(reset, "pfr") == 0) { | if (strcmp(reset, "pfr") == 0) { | ||||
reset_message = "Requesting a PF reset"; | reset_message = "Requesting a PF reset"; | ||||
reset_type = ICE_RESET_PFR; | reset_type = ICE_RESET_PFR; | ||||
} else if (strcmp(reset, "corer") == 0) { | } else if (strcmp(reset, "corer") == 0) { | ||||
reset_message = "Initiating a CORE reset"; | reset_message = "Initiating a CORE reset"; | ||||
reset_type = ICE_RESET_CORER; | reset_type = ICE_RESET_CORER; | ||||
} else if (strcmp(reset, "globr") == 0) { | } else if (strcmp(reset, "globr") == 0) { | ||||
▲ Show 20 Lines • Show All 1,081 Lines • ▼ Show 20 Lines | |||||
* Return a string representing the requested FEC mode. | * Return a string representing the requested FEC mode. | ||||
*/ | */ | ||||
static const char * | static const char * | ||||
ice_requested_fec_mode(struct ice_port_info *pi) | ice_requested_fec_mode(struct ice_port_info *pi) | ||||
{ | { | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | ||||
enum ice_status status; | enum ice_status status; | ||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_SW_CFG, | status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, | ||||
&pcaps, NULL); | &pcaps, NULL); | ||||
if (status) | if (status) | ||||
/* Just report unknown if we can't get capabilities */ | /* Just report unknown if we can't get capabilities */ | ||||
return "Unknown"; | return "Unknown"; | ||||
/* Check if RS-FEC has been requested first */ | /* Check if RS-FEC has been requested first */ | ||||
if (pcaps.link_fec_options & (ICE_AQC_PHY_FEC_25G_RS_528_REQ | | if (pcaps.link_fec_options & (ICE_AQC_PHY_FEC_25G_RS_528_REQ | | ||||
ICE_AQC_PHY_FEC_25G_RS_544_REQ)) | ICE_AQC_PHY_FEC_25G_RS_544_REQ)) | ||||
▲ Show 20 Lines • Show All 907 Lines • ▼ Show 20 Lines | device_printf(dev, | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
return; | return; | ||||
} | } | ||||
if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) { | if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) { | ||||
ice_clear_state(&sc->state, ICE_STATE_NO_MEDIA); | ice_clear_state(&sc->state, ICE_STATE_NO_MEDIA); | ||||
/* Apply default link settings */ | /* Apply default link settings */ | ||||
ice_apply_saved_phy_cfg(sc); | ice_apply_saved_phy_cfg(sc, ICE_APPLY_LS_FEC_FC); | ||||
} else { | } else { | ||||
/* Set link down, and poll for media available in timer. This prevents the | /* Set link down, and poll for media available in timer. This prevents the | ||||
* driver from receiving spurious link-related events. | * driver from receiving spurious link-related events. | ||||
*/ | */ | ||||
ice_set_state(&sc->state, ICE_STATE_NO_MEDIA); | ice_set_state(&sc->state, ICE_STATE_NO_MEDIA); | ||||
status = ice_aq_set_link_restart_an(pi, false, NULL); | status = ice_aq_set_link_restart_an(pi, false, NULL); | ||||
if (status != ICE_SUCCESS) | if (status != ICE_SUCCESS) | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: ice_aq_set_link_restart_an: status %s, aq_err %s\n", | "%s: ice_aq_set_link_restart_an: status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* ice_apply_saved_phy_req_to_cfg -- Write saved user PHY settings to cfg data | * ice_apply_saved_phy_req_to_cfg -- Write saved user PHY settings to cfg data | ||||
* @pi: port info struct | * @sc: device private structure | ||||
* @pcaps: TOPO_CAPS capability data to use for defaults | |||||
* @cfg: new PHY config data to be modified | * @cfg: new PHY config data to be modified | ||||
* | * | ||||
* Applies user settings for advertised speeds to the PHY type fields in the | * Applies user settings for advertised speeds to the PHY type fields in the | ||||
* supplied PHY config struct. It uses the data from pcaps to check if the | * supplied PHY config struct. It uses the data from pcaps to check if the | ||||
* saved settings are invalid and uses the pcaps data instead if they are | * saved settings are invalid and uses the pcaps data instead if they are | ||||
* invalid. | * invalid. | ||||
*/ | */ | ||||
static void | static int | ||||
ice_apply_saved_phy_req_to_cfg(struct ice_port_info *pi, | ice_apply_saved_phy_req_to_cfg(struct ice_softc *sc, | ||||
struct ice_aqc_get_phy_caps_data *pcaps, | |||||
struct ice_aqc_set_phy_cfg_data *cfg) | struct ice_aqc_set_phy_cfg_data *cfg) | ||||
{ | { | ||||
struct ice_phy_data phy_data = { 0 }; | |||||
struct ice_port_info *pi = sc->hw.port_info; | |||||
u64 phy_low = 0, phy_high = 0; | u64 phy_low = 0, phy_high = 0; | ||||
u16 link_speeds; | |||||
int ret; | |||||
ice_update_phy_type(&phy_low, &phy_high, pi->phy.curr_user_speed_req); | link_speeds = pi->phy.curr_user_speed_req; | ||||
cfg->phy_type_low = pcaps->phy_type_low & htole64(phy_low); | |||||
cfg->phy_type_high = pcaps->phy_type_high & htole64(phy_high); | |||||
/* Can't use saved user speed request; use NVM default PHY capabilities */ | if (ice_is_bit_set(sc->feat_en, ICE_FEATURE_LINK_MGMT_VER_2)) { | ||||
if (!cfg->phy_type_low && !cfg->phy_type_high) { | memset(&phy_data, 0, sizeof(phy_data)); | ||||
cfg->phy_type_low = pcaps->phy_type_low; | phy_data.report_mode = ICE_AQC_REPORT_DFLT_CFG; | ||||
cfg->phy_type_high = pcaps->phy_type_high; | phy_data.user_speeds_orig = link_speeds; | ||||
ret = ice_intersect_phy_types_and_speeds(sc, &phy_data); | |||||
if (ret != 0) { | |||||
/* Error message already printed within function */ | |||||
return (ret); | |||||
} | } | ||||
phy_low = phy_data.phy_low_intr; | |||||
phy_high = phy_data.phy_high_intr; | |||||
if (link_speeds == 0 || phy_data.user_speeds_intr) | |||||
goto finalize_link_speed; | |||||
if (ice_is_bit_set(sc->feat_en, ICE_FEATURE_LENIENT_LINK_MODE)) { | |||||
memset(&phy_data, 0, sizeof(phy_data)); | |||||
phy_data.report_mode = ICE_AQC_REPORT_TOPO_CAP_NO_MEDIA; | |||||
phy_data.user_speeds_orig = link_speeds; | |||||
ret = ice_intersect_phy_types_and_speeds(sc, &phy_data); | |||||
if (ret != 0) { | |||||
/* Error message already printed within function */ | |||||
return (ret); | |||||
} | } | ||||
phy_low = phy_data.phy_low_intr; | |||||
phy_high = phy_data.phy_high_intr; | |||||
if (!phy_data.user_speeds_intr) { | |||||
phy_low = phy_data.phy_low_orig; | |||||
phy_high = phy_data.phy_high_orig; | |||||
} | |||||
goto finalize_link_speed; | |||||
} | |||||
/* If we're here, then it means the benefits of Version 2 | |||||
* link management aren't utilized. We fall through to | |||||
* handling Strict Link Mode the same as Version 1 link | |||||
* management. | |||||
*/ | |||||
} | |||||
memset(&phy_data, 0, sizeof(phy_data)); | |||||
if ((link_speeds == 0) && | |||||
(sc->ldo_tlv.phy_type_low || sc->ldo_tlv.phy_type_high)) | |||||
phy_data.report_mode = ICE_AQC_REPORT_TOPO_CAP_NO_MEDIA; | |||||
else | |||||
phy_data.report_mode = ICE_AQC_REPORT_TOPO_CAP_MEDIA; | |||||
phy_data.user_speeds_orig = link_speeds; | |||||
ret = ice_intersect_phy_types_and_speeds(sc, &phy_data); | |||||
if (ret != 0) { | |||||
/* Error message already printed within function */ | |||||
return (ret); | |||||
} | |||||
phy_low = phy_data.phy_low_intr; | |||||
phy_high = phy_data.phy_high_intr; | |||||
if (!ice_is_bit_set(sc->feat_en, ICE_FEATURE_LENIENT_LINK_MODE)) { | |||||
if (phy_low == 0 && phy_high == 0) { | |||||
device_printf(sc->dev, | |||||
"The selected speed is not supported by the current media. Please select a link speed that is supported by the current media.\n"); | |||||
return (EINVAL); | |||||
} | |||||
} else { | |||||
if (link_speeds == 0) { | |||||
if (sc->ldo_tlv.phy_type_low & phy_low || | |||||
sc->ldo_tlv.phy_type_high & phy_high) { | |||||
phy_low &= sc->ldo_tlv.phy_type_low; | |||||
phy_high &= sc->ldo_tlv.phy_type_high; | |||||
} | |||||
} else if (phy_low == 0 && phy_high == 0) { | |||||
memset(&phy_data, 0, sizeof(phy_data)); | |||||
phy_data.report_mode = ICE_AQC_REPORT_TOPO_CAP_NO_MEDIA; | |||||
phy_data.user_speeds_orig = link_speeds; | |||||
ret = ice_intersect_phy_types_and_speeds(sc, &phy_data); | |||||
if (ret != 0) { | |||||
/* Error message already printed within function */ | |||||
return (ret); | |||||
} | |||||
phy_low = phy_data.phy_low_intr; | |||||
phy_high = phy_data.phy_high_intr; | |||||
if (!phy_data.user_speeds_intr) { | |||||
phy_low = phy_data.phy_low_orig; | |||||
phy_high = phy_data.phy_high_orig; | |||||
} | |||||
} | |||||
} | |||||
finalize_link_speed: | |||||
/* Cache new user settings for speeds */ | |||||
pi->phy.curr_user_speed_req = phy_data.user_speeds_intr; | |||||
cfg->phy_type_low = htole64(phy_low); | |||||
cfg->phy_type_high = htole64(phy_high); | |||||
return (ret); | |||||
} | |||||
/** | /** | ||||
* ice_apply_saved_fec_req_to_cfg -- Write saved user FEC mode to cfg data | * ice_apply_saved_fec_req_to_cfg -- Write saved user FEC mode to cfg data | ||||
* @pi: port info struct | * @sc: device private structure | ||||
* @pcaps: TOPO_CAPS capability data to use for defaults | |||||
* @cfg: new PHY config data to be modified | * @cfg: new PHY config data to be modified | ||||
* | * | ||||
* Applies user setting for FEC mode to PHY config struct. It uses the data | * Applies user setting for FEC mode to PHY config struct. It uses the data | ||||
* from pcaps to check if the saved settings are invalid and uses the pcaps | * from pcaps to check if the saved settings are invalid and uses the pcaps | ||||
* data instead if they are invalid. | * data instead if they are invalid. | ||||
*/ | */ | ||||
static void | static int | ||||
ice_apply_saved_fec_req_to_cfg(struct ice_port_info *pi, | ice_apply_saved_fec_req_to_cfg(struct ice_softc *sc, | ||||
struct ice_aqc_get_phy_caps_data *pcaps, | |||||
struct ice_aqc_set_phy_cfg_data *cfg) | struct ice_aqc_set_phy_cfg_data *cfg) | ||||
{ | { | ||||
ice_cfg_phy_fec(pi, cfg, pi->phy.curr_user_fec_req); | struct ice_port_info *pi = sc->hw.port_info; | ||||
enum ice_status status; | |||||
/* Can't use saved user FEC mode; use NVM default PHY capabilities */ | cfg->caps &= ~ICE_AQC_PHY_EN_AUTO_FEC; | ||||
if (cfg->link_fec_opt && | status = ice_cfg_phy_fec(pi, cfg, pi->phy.curr_user_fec_req); | ||||
!(cfg->link_fec_opt & pcaps->link_fec_options)) { | if (status) | ||||
cfg->caps |= pcaps->caps & ICE_AQC_PHY_EN_AUTO_FEC; | return (EIO); | ||||
cfg->link_fec_opt = pcaps->link_fec_options; | |||||
return (0); | |||||
} | } | ||||
} | |||||
/** | /** | ||||
* ice_apply_saved_fc_req_to_cfg -- Write saved user flow control mode to cfg data | * ice_apply_saved_fc_req_to_cfg -- Write saved user flow control mode to cfg data | ||||
* @pi: port info struct | * @pi: port info struct | ||||
* @cfg: new PHY config data to be modified | * @cfg: new PHY config data to be modified | ||||
* | * | ||||
* Applies user setting for flow control mode to PHY config struct. There are | * Applies user setting for flow control mode to PHY config struct. There are | ||||
* no invalid flow control mode settings; if there are, then this function | * no invalid flow control mode settings; if there are, then this function | ||||
* treats them like "ICE_FC_NONE". | * treats them like "ICE_FC_NONE". | ||||
*/ | */ | ||||
static void | static void | ||||
ice_apply_saved_fc_req_to_cfg(struct ice_port_info *pi, | ice_apply_saved_fc_req_to_cfg(struct ice_port_info *pi, | ||||
struct ice_aqc_set_phy_cfg_data *cfg) | struct ice_aqc_set_phy_cfg_data *cfg) | ||||
{ | { | ||||
cfg->caps &= ~(ICE_AQ_PHY_ENA_TX_PAUSE_ABILITY | | cfg->caps &= ~(ICE_AQ_PHY_ENA_TX_PAUSE_ABILITY | | ||||
ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY); | ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY); | ||||
switch (pi->phy.curr_user_fc_req) { | switch (pi->phy.curr_user_fc_req) { | ||||
case ICE_FC_FULL: | case ICE_FC_FULL: | ||||
cfg->caps |= ICE_AQ_PHY_ENA_TX_PAUSE_ABILITY | | cfg->caps |= ICE_AQ_PHY_ENA_TX_PAUSE_ABILITY | | ||||
ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY; | ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY; | ||||
break; | break; | ||||
case ICE_FC_RX_PAUSE: | case ICE_FC_RX_PAUSE: | ||||
cfg->caps |= ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY; | cfg->caps |= ICE_AQ_PHY_ENA_RX_PAUSE_ABILITY; | ||||
break; | break; | ||||
case ICE_FC_TX_PAUSE: | case ICE_FC_TX_PAUSE: | ||||
cfg->caps |= ICE_AQ_PHY_ENA_TX_PAUSE_ABILITY; | cfg->caps |= ICE_AQ_PHY_ENA_TX_PAUSE_ABILITY; | ||||
break; | break; | ||||
default: | default: | ||||
/* ICE_FC_NONE */ | /* ICE_FC_NONE */ | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* ice_apply_saved_user_req_to_cfg -- Apply all saved user settings to AQ cfg data | |||||
* @pi: port info struct | |||||
* @pcaps: TOPO_CAPS capability data to use for defaults | |||||
* @cfg: new PHY config data to be modified | |||||
* | |||||
* Applies user settings for advertised speeds, FEC mode, and flow control | |||||
* mode to the supplied PHY config struct; it uses the data from pcaps to check | |||||
* if the saved settings are invalid and uses the pcaps data instead if they | |||||
* are invalid. | |||||
*/ | |||||
static void | |||||
ice_apply_saved_user_req_to_cfg(struct ice_port_info *pi, | |||||
struct ice_aqc_get_phy_caps_data *pcaps, | |||||
struct ice_aqc_set_phy_cfg_data *cfg) | |||||
{ | |||||
ice_apply_saved_phy_req_to_cfg(pi, pcaps, cfg); | |||||
ice_apply_saved_fec_req_to_cfg(pi, pcaps, cfg); | |||||
ice_apply_saved_fc_req_to_cfg(pi, cfg); | |||||
} | |||||
/** | |||||
* ice_apply_saved_phy_cfg -- Re-apply user PHY config settings | * ice_apply_saved_phy_cfg -- Re-apply user PHY config settings | ||||
* @sc: device private structure | * @sc: device private structure | ||||
* @settings: which settings to apply | |||||
* | * | ||||
* Takes the saved user PHY config settings, overwrites the NVM | * Applies user settings for advertised speeds, FEC mode, and flow | ||||
* default with them if they're valid, and uses the Set PHY Config AQ command | * control mode to a PHY config struct; it uses the data from pcaps | ||||
* to apply them. | * to check if the saved settings are invalid and uses the pcaps | ||||
* data instead if they are invalid. | |||||
* | * | ||||
* Intended for use when media is inserted. | * For things like sysctls where only one setting needs to be | ||||
* | * updated, the bitmap allows the caller to specify which setting | ||||
* @pre Port has media available | * to update. | ||||
*/ | */ | ||||
void | int | ||||
ice_apply_saved_phy_cfg(struct ice_softc *sc) | ice_apply_saved_phy_cfg(struct ice_softc *sc, u8 settings) | ||||
{ | { | ||||
struct ice_aqc_set_phy_cfg_data cfg = { 0 }; | struct ice_aqc_set_phy_cfg_data cfg = { 0 }; | ||||
struct ice_port_info *pi = sc->hw.port_info; | struct ice_port_info *pi = sc->hw.port_info; | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
u64 phy_low, phy_high; | |||||
enum ice_status status; | enum ice_status status; | ||||
enum ice_fec_mode dflt_fec_mode; | |||||
enum ice_fc_mode dflt_fc_mode; | |||||
u16 dflt_user_speed; | |||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP, | if (!settings || settings > ICE_APPLY_LS_FEC_FC) { | ||||
ice_debug(hw, ICE_DBG_LINK, "Settings out-of-bounds: %u\n", | |||||
settings); | |||||
} | |||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, | |||||
&pcaps, NULL); | &pcaps, NULL); | ||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: ice_aq_get_phy_caps (TOPO_CAP) failed; status %s, aq_err %s\n", | "%s: ice_aq_get_phy_caps (ACTIVE) failed; status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
return; | return (EIO); | ||||
} | } | ||||
phy_low = le64toh(pcaps.phy_type_low); | |||||
phy_high = le64toh(pcaps.phy_type_high); | |||||
/* Save off initial config parameters */ | |||||
dflt_user_speed = ice_aq_phy_types_to_link_speeds(phy_low, phy_high); | |||||
dflt_fec_mode = ice_caps_to_fec_mode(pcaps.caps, pcaps.link_fec_options); | |||||
dflt_fc_mode = ice_caps_to_fc_mode(pcaps.caps); | |||||
/* Setup new PHY config */ | /* Setup new PHY config */ | ||||
ice_copy_phy_caps_to_cfg(pi, &pcaps, &cfg); | ice_copy_phy_caps_to_cfg(pi, &pcaps, &cfg); | ||||
/* Apply settings requested by user */ | /* On error, restore active configuration values */ | ||||
ice_apply_saved_user_req_to_cfg(pi, &pcaps, &cfg); | if ((settings & ICE_APPLY_LS) && | ||||
ice_apply_saved_phy_req_to_cfg(sc, &cfg)) { | |||||
pi->phy.curr_user_speed_req = dflt_user_speed; | |||||
cfg.phy_type_low = pcaps.phy_type_low; | |||||
cfg.phy_type_high = pcaps.phy_type_high; | |||||
} | |||||
if ((settings & ICE_APPLY_FEC) && | |||||
ice_apply_saved_fec_req_to_cfg(sc, &cfg)) { | |||||
pi->phy.curr_user_fec_req = dflt_fec_mode; | |||||
} | |||||
if (settings & ICE_APPLY_FC) { | |||||
/* No real error indicators for this process, | |||||
* so we'll just have to assume it works. */ | |||||
ice_apply_saved_fc_req_to_cfg(pi, &cfg); | |||||
} | |||||
/* Enable link and re-negotiate it */ | /* Enable link and re-negotiate it */ | ||||
cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT | ICE_AQ_PHY_ENA_LINK; | cfg.caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT | ICE_AQ_PHY_ENA_LINK; | ||||
status = ice_aq_set_phy_cfg(hw, pi, &cfg, NULL); | status = ice_aq_set_phy_cfg(hw, pi, &cfg, NULL); | ||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
/* Don't indicate failure if there's no media in the port. | |||||
* The settings have been saved and will apply when media | |||||
* is inserted. | |||||
*/ | |||||
if ((status == ICE_ERR_AQ_ERROR) && | if ((status == ICE_ERR_AQ_ERROR) && | ||||
(hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY)) | (hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY)) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: User PHY cfg not applied; no media in port\n", | "%s: Setting will be applied when media is inserted\n", | ||||
__func__); | __func__); | ||||
else | return (0); | ||||
} else { | |||||
device_printf(dev, | device_printf(dev, | ||||
"%s: ice_aq_set_phy_cfg failed; status %s, aq_err %s\n", | "%s: ice_aq_set_phy_cfg failed; status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
return (EIO); | |||||
} | } | ||||
} | } | ||||
return (0); | |||||
} | |||||
/** | /** | ||||
* ice_print_ldo_tlv - Print out LDO TLV information | * ice_print_ldo_tlv - Print out LDO TLV information | ||||
* @sc: device private structure | * @sc: device private structure | ||||
* @tlv: LDO TLV information from the adapter NVM | * @tlv: LDO TLV information from the adapter NVM | ||||
* | * | ||||
* Dump out the information in tlv to the kernel message buffer; intended for | * Dump out the information in tlv to the kernel message buffer; intended for | ||||
* debugging purposes. | * debugging purposes. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | ice_set_link_management_mode(struct ice_softc *sc) | ||||
if (sc->hw.debug_mask & ICE_DBG_LINK) | if (sc->hw.debug_mask & ICE_DBG_LINK) | ||||
ice_print_ldo_tlv(sc, &tlv); | ice_print_ldo_tlv(sc, &tlv); | ||||
/* Set lenient link mode */ | /* Set lenient link mode */ | ||||
if (ice_is_bit_set(sc->feat_cap, ICE_FEATURE_LENIENT_LINK_MODE) && | if (ice_is_bit_set(sc->feat_cap, ICE_FEATURE_LENIENT_LINK_MODE) && | ||||
(!(tlv.options & ICE_LINK_OVERRIDE_STRICT_MODE))) | (!(tlv.options & ICE_LINK_OVERRIDE_STRICT_MODE))) | ||||
ice_set_bit(ICE_FEATURE_LENIENT_LINK_MODE, sc->feat_en); | ice_set_bit(ICE_FEATURE_LENIENT_LINK_MODE, sc->feat_en); | ||||
/* FW supports reporting a default configuration */ | |||||
if (ice_is_bit_set(sc->feat_cap, ICE_FEATURE_LINK_MGMT_VER_2) && | |||||
ice_fw_supports_report_dflt_cfg(&sc->hw)) { | |||||
ice_set_bit(ICE_FEATURE_LINK_MGMT_VER_2, sc->feat_en); | |||||
/* Knowing we're at a high enough firmware revision to | |||||
* support this link management configuration, we don't | |||||
* need to check/support earlier versions. | |||||
*/ | |||||
return; | |||||
} | |||||
/* Default overrides only work if in lenient link mode */ | /* Default overrides only work if in lenient link mode */ | ||||
if (ice_is_bit_set(sc->feat_cap, ICE_FEATURE_DEFAULT_OVERRIDE) && | if (ice_is_bit_set(sc->feat_cap, ICE_FEATURE_LINK_MGMT_VER_1) && | ||||
ice_is_bit_set(sc->feat_en, ICE_FEATURE_LENIENT_LINK_MODE) && | ice_is_bit_set(sc->feat_en, ICE_FEATURE_LENIENT_LINK_MODE) && | ||||
(tlv.options & ICE_LINK_OVERRIDE_EN)) | (tlv.options & ICE_LINK_OVERRIDE_EN)) | ||||
ice_set_bit(ICE_FEATURE_DEFAULT_OVERRIDE, sc->feat_en); | ice_set_bit(ICE_FEATURE_LINK_MGMT_VER_1, sc->feat_en); | ||||
/* Cache the LDO TLV structure in the driver, since it won't change | /* Cache the LDO TLV structure in the driver, since it | ||||
* during the driver's lifetime. | * won't change during the driver's lifetime. | ||||
*/ | */ | ||||
sc->ldo_tlv = tlv; | sc->ldo_tlv = tlv; | ||||
} | } | ||||
/** | /** | ||||
* ice_init_saved_phy_cfg -- Set cached user PHY cfg settings with NVM defaults | * ice_init_saved_phy_cfg -- Set cached user PHY cfg settings with NVM defaults | ||||
* @sc: device private structure | * @sc: device private structure | ||||
* | * | ||||
Show All 9 Lines | |||||
ice_init_saved_phy_cfg(struct ice_softc *sc) | ice_init_saved_phy_cfg(struct ice_softc *sc) | ||||
{ | { | ||||
struct ice_port_info *pi = sc->hw.port_info; | struct ice_port_info *pi = sc->hw.port_info; | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
enum ice_status status; | enum ice_status status; | ||||
u64 phy_low, phy_high; | u64 phy_low, phy_high; | ||||
u8 report_mode = ICE_AQC_REPORT_TOPO_CAP_MEDIA; | |||||
status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP, | if (ice_is_bit_set(sc->feat_en, ICE_FEATURE_LINK_MGMT_VER_2)) | ||||
&pcaps, NULL); | report_mode = ICE_AQC_REPORT_DFLT_CFG; | ||||
status = ice_aq_get_phy_caps(pi, false, report_mode, &pcaps, NULL); | |||||
if (status != ICE_SUCCESS) { | if (status != ICE_SUCCESS) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: ice_aq_get_phy_caps (TOPO_CAP) failed; status %s, aq_err %s\n", | "%s: ice_aq_get_phy_caps (%s) failed; status %s, aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, | ||||
report_mode == ICE_AQC_REPORT_DFLT_CFG ? "DFLT" : "w/MEDIA", | |||||
ice_status_str(status), | |||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
return; | return; | ||||
} | } | ||||
phy_low = le64toh(pcaps.phy_type_low); | phy_low = le64toh(pcaps.phy_type_low); | ||||
phy_high = le64toh(pcaps.phy_type_high); | phy_high = le64toh(pcaps.phy_type_high); | ||||
/* Save off initial config parameters */ | /* Save off initial config parameters */ | ||||
pi->phy.curr_user_speed_req = | pi->phy.curr_user_speed_req = | ||||
ice_aq_phy_types_to_sysctl_speeds(phy_low, phy_high); | ice_aq_phy_types_to_link_speeds(phy_low, phy_high); | ||||
pi->phy.curr_user_fec_req = ice_caps_to_fec_mode(pcaps.caps, | pi->phy.curr_user_fec_req = ice_caps_to_fec_mode(pcaps.caps, | ||||
pcaps.link_fec_options); | pcaps.link_fec_options); | ||||
pi->phy.curr_user_fc_req = ice_caps_to_fc_mode(pcaps.caps); | pi->phy.curr_user_fc_req = ice_caps_to_fc_mode(pcaps.caps); | ||||
} | } | ||||
/** | /** | ||||
* ice_module_init - Driver callback to handle module load | * ice_module_init - Driver callback to handle module load | ||||
* | * | ||||
▲ Show 20 Lines • Show All 163 Lines • ▼ Show 20 Lines | |||||
* Read from the SFF eeprom in the module for this PF's port. For more details | * Read from the SFF eeprom in the module for this PF's port. For more details | ||||
* on the contents of an SFF eeprom, refer to SFF-8724 (SFP), SFF-8636 (QSFP), | * on the contents of an SFF eeprom, refer to SFF-8724 (SFP), SFF-8636 (QSFP), | ||||
* and SFF-8024 (both). | * and SFF-8024 (both). | ||||
*/ | */ | ||||
int | int | ||||
ice_read_sff_eeprom(struct ice_softc *sc, u16 dev_addr, u16 offset, u8* data, u16 length) | ice_read_sff_eeprom(struct ice_softc *sc, u16 dev_addr, u16 offset, u8* data, u16 length) | ||||
{ | { | ||||
struct ice_hw *hw = &sc->hw; | struct ice_hw *hw = &sc->hw; | ||||
int error = 0, retries = 0; | int ret = 0, retries = 0; | ||||
enum ice_status status; | enum ice_status status; | ||||
if (length > 16) | if (length > 16) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (ice_test_state(&sc->state, ICE_STATE_RECOVERY_MODE)) | if (ice_test_state(&sc->state, ICE_STATE_RECOVERY_MODE)) | ||||
return (ENOSYS); | return (ENOSYS); | ||||
if (ice_test_state(&sc->state, ICE_STATE_NO_MEDIA)) | if (ice_test_state(&sc->state, ICE_STATE_NO_MEDIA)) | ||||
return (ENXIO); | return (ENXIO); | ||||
do { | do { | ||||
status = ice_aq_sff_eeprom(hw, 0, dev_addr, | status = ice_aq_sff_eeprom(hw, 0, dev_addr, | ||||
offset, 0, 0, data, length, | offset, 0, 0, data, length, | ||||
false, NULL); | false, NULL); | ||||
if (!status) { | if (!status) { | ||||
error = 0; | ret = 0; | ||||
break; | break; | ||||
} | } | ||||
if (status == ICE_ERR_AQ_ERROR && | if (status == ICE_ERR_AQ_ERROR && | ||||
hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY) { | hw->adminq.sq_last_status == ICE_AQ_RC_EBUSY) { | ||||
error = EBUSY; | ret = EBUSY; | ||||
continue; | continue; | ||||
} | } | ||||
if (status == ICE_ERR_AQ_ERROR && | if (status == ICE_ERR_AQ_ERROR && | ||||
hw->adminq.sq_last_status == ICE_AQ_RC_EACCES) { | hw->adminq.sq_last_status == ICE_AQ_RC_EACCES) { | ||||
/* FW says I2C access isn't supported */ | /* FW says I2C access isn't supported */ | ||||
error = EACCES; | ret = EACCES; | ||||
break; | break; | ||||
} | } | ||||
if (status == ICE_ERR_AQ_ERROR && | if (status == ICE_ERR_AQ_ERROR && | ||||
hw->adminq.sq_last_status == ICE_AQ_RC_EPERM) { | hw->adminq.sq_last_status == ICE_AQ_RC_EPERM) { | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"%s: Module pointer location specified in command does not permit the required operation.\n", | "%s: Module pointer location specified in command does not permit the required operation.\n", | ||||
__func__); | __func__); | ||||
error = EPERM; | ret = EPERM; | ||||
break; | break; | ||||
} else { | } else { | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"%s: Error reading I2C data: err %s aq_err %s\n", | "%s: Error reading I2C data: err %s aq_err %s\n", | ||||
__func__, ice_status_str(status), | __func__, ice_status_str(status), | ||||
ice_aq_str(hw->adminq.sq_last_status)); | ice_aq_str(hw->adminq.sq_last_status)); | ||||
error = EIO; | ret = EIO; | ||||
break; | break; | ||||
} | } | ||||
} while (retries++ < ICE_I2C_MAX_RETRIES); | } while (retries++ < ICE_I2C_MAX_RETRIES); | ||||
if (error == EBUSY) | if (ret == EBUSY) | ||||
device_printf(sc->dev, | device_printf(sc->dev, | ||||
"%s: Error reading I2C data after %d retries\n", | "%s: Error reading I2C data after %d retries\n", | ||||
__func__, ICE_I2C_MAX_RETRIES); | __func__, ICE_I2C_MAX_RETRIES); | ||||
return (error); | return (ret); | ||||
} | } | ||||
/** | /** | ||||
* ice_handle_i2c_req - Driver independent I2C request handler | * ice_handle_i2c_req - Driver independent I2C request handler | ||||
* @sc: device softc | * @sc: device softc | ||||
* @req: The I2C parameters to use | * @req: The I2C parameters to use | ||||
* | * | ||||
* Read from the port's I2C eeprom using the parameters from the ioctl. | * Read from the port's I2C eeprom using the parameters from the ioctl. | ||||
Show All 22 Lines | |||||
* RX power | 104-105 | 50-51..56-57 | * RX power | 104-105 | 50-51..56-57 | ||||
*/ | */ | ||||
static int | static int | ||||
ice_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS) | ice_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ice_softc *sc = (struct ice_softc *)arg1; | struct ice_softc *sc = (struct ice_softc *)arg1; | ||||
device_t dev = sc->dev; | device_t dev = sc->dev; | ||||
struct sbuf *sbuf; | struct sbuf *sbuf; | ||||
int error = 0; | int ret; | ||||
u8 data[16]; | u8 data[16]; | ||||
UNREFERENCED_PARAMETER(arg2); | UNREFERENCED_PARAMETER(arg2); | ||||
UNREFERENCED_PARAMETER(oidp); | UNREFERENCED_PARAMETER(oidp); | ||||
if (ice_driver_is_detaching(sc)) | if (ice_driver_is_detaching(sc)) | ||||
return (ESHUTDOWN); | return (ESHUTDOWN); | ||||
if (req->oldptr == NULL) { | if (req->oldptr == NULL) { | ||||
error = SYSCTL_OUT(req, 0, 128); | ret = SYSCTL_OUT(req, 0, 128); | ||||
return (error); | return (ret); | ||||
} | } | ||||
error = ice_read_sff_eeprom(sc, 0xA0, 0, data, 1); | ret = ice_read_sff_eeprom(sc, 0xA0, 0, data, 1); | ||||
if (error) | if (ret) | ||||
return (error); | return (ret); | ||||
/* 0x3 for SFP; 0xD/0x11 for QSFP+/QSFP28 */ | /* 0x3 for SFP; 0xD/0x11 for QSFP+/QSFP28 */ | ||||
if (data[0] == 0x3) { | if (data[0] == 0x3) { | ||||
/* | /* | ||||
* Check for: | * Check for: | ||||
* - Internally calibrated data | * - Internally calibrated data | ||||
* - Diagnostic monitoring is implemented | * - Diagnostic monitoring is implemented | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | if (sc->pf_imap) { | ||||
sc->pf_imap = NULL; | sc->pf_imap = NULL; | ||||
} | } | ||||
ice_resmgr_destroy(&sc->imgr); | ice_resmgr_destroy(&sc->imgr); | ||||
} | } | ||||
/** | /** | ||||
* ice_apply_supported_speed_filter - Mask off unsupported speeds | * ice_apply_supported_speed_filter - Mask off unsupported speeds | ||||
* @phy_type_low: bit-field for the low quad word of PHY types | * @report_speeds: bit-field for the desired link speeds | ||||
* @phy_type_high: bit-field for the high quad word of PHY types | |||||
* | * | ||||
* Given the two quad words containing the supported PHY types, | * Given a bitmap of the desired lenient mode link speeds, | ||||
* this function will mask off the speeds that are not currently | * this function will mask off the speeds that are not currently | ||||
* supported by the device. | * supported by the device. | ||||
*/ | */ | ||||
static void | static u16 | ||||
ice_apply_supported_speed_filter(u64 *phy_type_low, u64 *phy_type_high) | ice_apply_supported_speed_filter(u16 report_speeds) | ||||
{ | { | ||||
u64 phylow_mask; | u16 speed_mask; | ||||
/* We won't offer anything lower than 1G for any part, | /* We won't offer anything lower than 1G for any part, | ||||
* but we also won't offer anything under 25G for 100G | * but we also won't offer anything under 25G for 100G | ||||
* parts. | * parts or under 10G for 50G parts. | ||||
*/ | */ | ||||
phylow_mask = ~(ICE_PHY_TYPE_LOW_1000BASE_T - 1); | speed_mask = ~((u16)ICE_AQ_LINK_SPEED_1000MB - 1); | ||||
if (*phy_type_high || | if (report_speeds & ICE_AQ_LINK_SPEED_50GB) | ||||
*phy_type_low & ~(ICE_PHY_TYPE_LOW_100GBASE_CR4 - 1)) | speed_mask = ~((u16)ICE_AQ_LINK_SPEED_10GB - 1); | ||||
phylow_mask = ~(ICE_PHY_TYPE_LOW_25GBASE_T - 1); | if (report_speeds & ICE_AQ_LINK_SPEED_100GB) | ||||
*phy_type_low &= phylow_mask; | speed_mask = ~((u16)ICE_AQ_LINK_SPEED_25GB - 1); | ||||
return (report_speeds & speed_mask); | |||||
} | } | ||||
/** | /** | ||||
* ice_get_phy_types - Report appropriate PHY types | * ice_init_health_events - Enable FW health event reporting | ||||
* @sc: device softc structure | * @sc: device softc | ||||
* @phy_type_low: bit-field for the low quad word of PHY types | |||||
* @phy_type_high: bit-field for the high quad word of PHY types | |||||
* | * | ||||
* Populate the two quad words with bits representing the PHY types | * Will try to enable firmware health event reporting, but shouldn't | ||||
* supported by the device. This is really just a wrapper around | * cause any grief (to the caller) if this fails. | ||||
* the ice_aq_get_phy_caps() that chooses the appropriate report | |||||
* mode (lenient or strict) and reports back only the relevant PHY | |||||
* types. In lenient mode the capabilities are retrieved with the | |||||
* NVM_CAP report mode, otherwise they're retrieved using the | |||||
* TOPO_CAP report mode (NVM intersected with current media). | |||||
* | |||||
* @returns 0 on success, or an error code on failure. | |||||
*/ | */ | ||||
static enum ice_status | void | ||||
ice_get_phy_types(struct ice_softc *sc, u64 *phy_type_low, u64 *phy_type_high) | ice_init_health_events(struct ice_softc *sc) | ||||
{ | { | ||||
struct ice_aqc_get_phy_caps_data pcaps = { 0 }; | |||||
struct ice_port_info *pi = sc->hw.port_info; | |||||
device_t dev = sc->dev; | |||||
enum ice_status status; | enum ice_status status; | ||||
u8 report_mode; | u8 health_mask; | ||||
if (ice_is_bit_set(sc->feat_en, ICE_FEATURE_LENIENT_LINK_MODE)) | if (!ice_is_bit_set(sc->feat_cap, ICE_FEATURE_HEALTH_STATUS)) | ||||
report_mode = ICE_AQC_REPORT_NVM_CAP; | return; | ||||
else | |||||
report_mode = ICE_AQC_REPORT_TOPO_CAP; | health_mask = ICE_AQC_HEALTH_STATUS_SET_PF_SPECIFIC_MASK | | ||||
status = ice_aq_get_phy_caps(pi, false, report_mode, &pcaps, NULL); | ICE_AQC_HEALTH_STATUS_SET_GLOBAL_MASK; | ||||
if (status != ICE_SUCCESS) { | |||||
device_printf(dev, | status = ice_aq_set_health_status_config(&sc->hw, health_mask, NULL); | ||||
"%s: ice_aq_get_phy_caps (%s) failed; status %s, aq_err %s\n", | if (status) | ||||
__func__, (report_mode) ? "TOPO_CAP" : "NVM_CAP", | device_printf(sc->dev, | ||||
"Failed to enable firmware health events, err %s aq_err %s\n", | |||||
ice_status_str(status), | ice_status_str(status), | ||||
ice_aq_str(sc->hw.adminq.sq_last_status)); | ice_aq_str(sc->hw.adminq.sq_last_status)); | ||||
return (status); | else | ||||
ice_set_bit(ICE_FEATURE_HEALTH_STATUS, sc->feat_en); | |||||
} | } | ||||
*phy_type_low = le64toh(pcaps.phy_type_low); | /** | ||||
*phy_type_high = le64toh(pcaps.phy_type_high); | * ice_print_health_status_string - Print message for given FW health event | ||||
* @dev: the PCIe device | |||||
* @elem: health status element containing status code | |||||
* | |||||
* A rather large list of possible health status codes and their associated | |||||
* messages. | |||||
*/ | |||||
static void | |||||
ice_print_health_status_string(device_t dev, | |||||
struct ice_aqc_health_status_elem *elem) | |||||
{ | |||||
u16 status_code = le16toh(elem->health_status_code); | |||||
return (ICE_SUCCESS); | switch (status_code) { | ||||
case ICE_AQC_HEALTH_STATUS_INFO_RECOVERY: | |||||
device_printf(dev, "The device is in firmware recovery mode.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_FLASH_ACCESS: | |||||
device_printf(dev, "The flash chip cannot be accessed.\n"); | |||||
device_printf(dev, "Possible Solution: If issue persists, call customer support.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_NVM_AUTH: | |||||
device_printf(dev, "NVM authentication failed.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_OROM_AUTH: | |||||
device_printf(dev, "Option ROM authentication failed.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_DDP_AUTH: | |||||
device_printf(dev, "DDP package failed.\n"); | |||||
device_printf(dev, "Possible Solution: Update to latest base driver and DDP package.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_NVM_COMPAT: | |||||
device_printf(dev, "NVM image is incompatible.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_OROM_COMPAT: | |||||
device_printf(dev, "Option ROM is incompatible.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_DCB_MIB: | |||||
device_printf(dev, "Supplied MIB file is invalid. DCB reverted to default configuration.\n"); | |||||
device_printf(dev, "Possible Solution: Disable FW-LLDP and check DCBx system configuration.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_STRICT: | |||||
device_printf(dev, "An unsupported module was detected.\n"); | |||||
device_printf(dev, "Possible Solution 1: Check your cable connection.\n"); | |||||
device_printf(dev, "Possible Solution 2: Change or replace the module or cable.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_MOD_TYPE: | |||||
device_printf(dev, "Module type is not supported.\n"); | |||||
device_printf(dev, "Possible Solution: Change or replace the module or cable.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_MOD_QUAL: | |||||
device_printf(dev, "Module is not qualified.\n"); | |||||
device_printf(dev, "Possible Solution 1: Check your cable connection.\n"); | |||||
device_printf(dev, "Possible Solution 2: Change or replace the module or cable.\n"); | |||||
device_printf(dev, "Possible Solution 3: Manually set speed and duplex.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_MOD_COMM: | |||||
device_printf(dev, "Device cannot communicate with the module.\n"); | |||||
device_printf(dev, "Possible Solution 1: Check your cable connection.\n"); | |||||
device_printf(dev, "Possible Solution 2: Change or replace the module or cable.\n"); | |||||
device_printf(dev, "Possible Solution 3: Manually set speed and duplex.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_MOD_CONFLICT: | |||||
device_printf(dev, "Unresolved module conflict.\n"); | |||||
device_printf(dev, "Possible Solution 1: Manually set speed/duplex or use Intel(R) Ethernet Port Configuration Tool to change the port option.\n"); | |||||
device_printf(dev, "Possible Solution 2: If the problem persists, use a cable/module that is found in the supported modules and cables list for this device.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_MOD_NOT_PRESENT: | |||||
device_printf(dev, "Module is not present.\n"); | |||||
device_printf(dev, "Possible Solution 1: Check that the module is inserted correctly.\n"); | |||||
device_printf(dev, "Possible Solution 2: If the problem persists, use a cable/module that is found in the supported modules and cables list for this device.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_INFO_MOD_UNDERUTILIZED: | |||||
device_printf(dev, "Underutilized module.\n"); | |||||
device_printf(dev, "Possible Solution 1: Change or replace the module or cable.\n"); | |||||
device_printf(dev, "Possible Solution 2: Use Intel(R) Ethernet Port Configuration Tool to change the port option.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_UNKNOWN_MOD_LENIENT: | |||||
device_printf(dev, "An unsupported module was detected.\n"); | |||||
device_printf(dev, "Possible Solution 1: Check your cable connection.\n"); | |||||
device_printf(dev, "Possible Solution 2: Change or replace the module or cable.\n"); | |||||
device_printf(dev, "Possible Solution 3: Manually set speed and duplex.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_INVALID_LINK_CFG: | |||||
device_printf(dev, "Invalid link configuration.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_PORT_ACCESS: | |||||
device_printf(dev, "Port hardware access error.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_PORT_UNREACHABLE: | |||||
device_printf(dev, "A port is unreachable.\n"); | |||||
device_printf(dev, "Possible Solution 1: Use Intel(R) Ethernet Port Configuration Tool to change the port option.\n"); | |||||
device_printf(dev, "Possible Solution 2: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_MOD_LIMITED: | |||||
device_printf(dev, "Port speed is limited due to module.\n"); | |||||
device_printf(dev, "Possible Solution: Change the module or use Intel(R) Ethernet Port Configuration Tool to configure the port option to match the current module speed.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_PARALLEL_FAULT: | |||||
device_printf(dev, "A parallel fault was detected.\n"); | |||||
device_printf(dev, "Possible Solution: Check link partner connection and configuration.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_INFO_PORT_SPEED_PHY_LIMITED: | |||||
device_printf(dev, "Port speed is limited by PHY capabilities.\n"); | |||||
device_printf(dev, "Possible Solution 1: Change the module to align to port option.\n"); | |||||
device_printf(dev, "Possible Solution 2: Use Intel(R) Ethernet Port Configuration Tool to change the port option.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_NETLIST_TOPO: | |||||
device_printf(dev, "LOM topology netlist is corrupted.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_NETLIST: | |||||
device_printf(dev, "Unrecoverable netlist error.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_TOPO_CONFLICT: | |||||
device_printf(dev, "Port topology conflict.\n"); | |||||
device_printf(dev, "Possible Solution 1: Use Intel(R) Ethernet Port Configuration Tool to change the port option.\n"); | |||||
device_printf(dev, "Possible Solution 2: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_LINK_HW_ACCESS: | |||||
device_printf(dev, "Unrecoverable hardware access error.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_LINK_RUNTIME: | |||||
device_printf(dev, "Unrecoverable runtime error.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
case ICE_AQC_HEALTH_STATUS_ERR_DNL_INIT: | |||||
device_printf(dev, "Link management engine failed to initialize.\n"); | |||||
device_printf(dev, "Possible Solution: Update to the latest NVM image.\n"); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
/** | |||||
* ice_handle_health_status_event - helper function to output health status | |||||
* @sc: device softc structure | |||||
* @event: event received on a control queue | |||||
* | |||||
* Prints out the appropriate string based on the given Health Status Event | |||||
* code. | |||||
*/ | |||||
static void | |||||
ice_handle_health_status_event(struct ice_softc *sc, | |||||
struct ice_rq_event_info *event) | |||||
{ | |||||
struct ice_aqc_health_status_elem *health_info; | |||||
u16 status_count; | |||||
int i; | |||||
if (!ice_is_bit_set(sc->feat_en, ICE_FEATURE_HEALTH_STATUS)) | |||||
return; | |||||
health_info = (struct ice_aqc_health_status_elem *)event->msg_buf; | |||||
status_count = le16toh(event->desc.params.get_health_status.health_status_count); | |||||
if (status_count > (event->buf_len / sizeof(*health_info))) { | |||||
device_printf(sc->dev, "Received a health status event with invalid event count\n"); | |||||
return; | |||||
} | |||||
for (i = 0; i < status_count; i++) { | |||||
ice_print_health_status_string(sc->dev, health_info); | |||||
health_info++; | |||||
} | |||||
} | } | ||||
/** | /** | ||||
* ice_set_default_local_lldp_mib - Set Local LLDP MIB to default settings | * ice_set_default_local_lldp_mib - Set Local LLDP MIB to default settings | ||||
* @sc: device softc structure | * @sc: device softc structure | ||||
* | * | ||||
* This function needs to be called after link up; it makes sure the FW | * This function needs to be called after link up; it makes sure the FW | ||||
* has certain PFC/DCB settings. This is intended to workaround a FW behavior | * has certain PFC/DCB settings. This is intended to workaround a FW behavior | ||||
Show All 40 Lines |