Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixl/ixl_pf_main.c
/****************************************************************************** | /****************************************************************************** | ||||
Copyright (c) 2013-2017, Intel Corporation | Copyright (c) 2013-2019, Intel Corporation | ||||
All rights reserved. | All rights reserved. | ||||
Redistribution and use in source and binary forms, with or without | Redistribution and use in source and binary forms, with or without | ||||
modification, are permitted provided that the following conditions are met: | modification, are permitted provided that the following conditions are met: | ||||
1. Redistributions of source code must retain the above copyright notice, | 1. Redistributions of source code must retain the above copyright notice, | ||||
this list of conditions and the following disclaimer. | this list of conditions and the following disclaimer. | ||||
2. Redistributions in binary form must reproduce the above copyright | 2. Redistributions in binary form must reproduce the above copyright | ||||
notice, this list of conditions and the following disclaimer in the | notice, this list of conditions and the following disclaimer in the | ||||
Show All 26 Lines | |||||
#endif | #endif | ||||
#ifdef IXL_IW | #ifdef IXL_IW | ||||
#include "ixl_iw.h" | #include "ixl_iw.h" | ||||
#include "ixl_iw_int.h" | #include "ixl_iw_int.h" | ||||
#endif | #endif | ||||
#ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
#include <net/netmap.h> | #include <dev/netmap/if_ixl_netmap.h> | ||||
#include <sys/selinfo.h> | |||||
#include <dev/netmap/netmap_kern.h> | |||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
static int ixl_vsi_setup_queue(struct ixl_vsi *, struct ixl_queue *, int); | static int ixl_vsi_setup_queue(struct ixl_vsi *, struct ixl_queue *, int); | ||||
static u64 ixl_max_aq_speed_to_value(u8); | static u64 ixl_max_aq_speed_to_value(u8); | ||||
static u8 ixl_convert_sysctl_aq_link_speed(u8, bool); | static u8 ixl_convert_sysctl_aq_link_speed(u8, bool); | ||||
static void ixl_sbuf_print_bytes(struct sbuf *, u8 *, int, int, bool); | static void ixl_sbuf_print_bytes(struct sbuf *, u8 *, int, int, bool); | ||||
static enum i40e_status_code ixl_set_lla(struct ixl_vsi *); | |||||
static const char * ixl_link_speed_string(u8 link_speed); | |||||
/* Sysctls */ | /* Sysctls */ | ||||
static int ixl_sysctl_set_flowcntl(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_set_flowcntl(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_set_advertise(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_set_advertise(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_supported_speeds(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_supported_speeds(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_current_speed(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_current_speed(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_unallocated_queues(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_unallocated_queues(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_pf_tx_itr(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_pf_tx_itr(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_pf_rx_itr(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_pf_rx_itr(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_eee_enable(SYSCTL_HANDLER_ARGS); | |||||
/* Debug Sysctls */ | /* Debug Sysctls */ | ||||
static int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_hkey(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_hkey(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_hena(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_hena(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_hlut(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_hlut(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_fw_link_management(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_fw_link_management(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_read_i2c_byte(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_read_i2c_byte(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_write_i2c_byte(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_write_i2c_byte(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_fec_fc_ability(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_fec_fc_ability(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_fec_rs_ability(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_fec_rs_ability(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_fec_fc_request(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_fec_fc_request(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_fec_rs_request(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_fec_rs_request(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_fec_auto_enable(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_fec_auto_enable(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_dump_debug_data(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_dump_debug_data(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_fw_lldp(SYSCTL_HANDLER_ARGS); | static int ixl_sysctl_fw_lldp(SYSCTL_HANDLER_ARGS); | ||||
#ifdef IXL_DEBUG | static int ixl_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS); | |||||
static int ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS); | |||||
#endif | |||||
#ifdef IXL_IW | #ifdef IXL_IW | ||||
extern int ixl_enable_iwarp; | extern int ixl_enable_iwarp; | ||||
extern int ixl_limit_iwarp_msix; | extern int ixl_limit_iwarp_msix; | ||||
#endif | #endif | ||||
const uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] = | const uint8_t ixl_bcast_addr[ETHER_ADDR_LEN] = | ||||
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | ixl_print_nvm_version(struct ixl_pf *pf) | ||||
sbuf = sbuf_new_auto(); | sbuf = sbuf_new_auto(); | ||||
ixl_nvm_version_str(hw, sbuf); | ixl_nvm_version_str(hw, sbuf); | ||||
sbuf_finish(sbuf); | sbuf_finish(sbuf); | ||||
device_printf(dev, "%s\n", sbuf_data(sbuf)); | device_printf(dev, "%s\n", sbuf_data(sbuf)); | ||||
sbuf_delete(sbuf); | sbuf_delete(sbuf); | ||||
} | } | ||||
bool | |||||
ixl_fw_recovery_mode(struct ixl_pf *pf) | |||||
{ | |||||
return (rd32(&pf->hw, I40E_GL_FWSTS) & I40E_GL_FWSTS_FWS1B_MASK); | |||||
} | |||||
static void | static void | ||||
ixl_configure_tx_itr(struct ixl_pf *pf) | ixl_configure_tx_itr(struct ixl_pf *pf) | ||||
{ | { | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
struct ixl_queue *que = vsi->queues; | struct ixl_queue *que = vsi->queues; | ||||
vsi->tx_itr_setting = pf->tx_itr; | vsi->tx_itr_setting = pf->tx_itr; | ||||
Show All 32 Lines | |||||
*/ | */ | ||||
void | void | ||||
ixl_configure_itr(struct ixl_pf *pf) | ixl_configure_itr(struct ixl_pf *pf) | ||||
{ | { | ||||
ixl_configure_tx_itr(pf); | ixl_configure_tx_itr(pf); | ||||
ixl_configure_rx_itr(pf); | ixl_configure_rx_itr(pf); | ||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* Init entry point | * Init entry point | ||||
* | * | ||||
* This routine is used in two ways. It is used by the stack as | * This routine is used in two ways. It is used by the stack as | ||||
* init entry point in network interface structure. It is also used | * init entry point in network interface structure. It is also used | ||||
* by the driver as a hw/sw initialization routine to get to a | * by the driver as a hw/sw initialization routine to get to a | ||||
* consistent state. | * consistent state. | ||||
* | * | ||||
* return 0 on success, positive on failure | * return 0 on success, positive on failure | ||||
**********************************************************************/ | **********************************************************************/ | ||||
void | void | ||||
ixl_init_locked(struct ixl_pf *pf) | ixl_init_locked(struct ixl_pf *pf) | ||||
{ | { | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
struct ifnet *ifp = vsi->ifp; | struct ifnet *ifp = vsi->ifp; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct i40e_filter_control_settings filter; | struct i40e_filter_control_settings filter; | ||||
u8 tmpaddr[ETHER_ADDR_LEN]; | |||||
int ret; | |||||
INIT_DEBUGOUT("ixl_init_locked: begin"); | INIT_DEBUGOUT("ixl_init_locked: begin"); | ||||
IXL_PF_LOCK_ASSERT(pf); | IXL_PF_LOCK_ASSERT(pf); | ||||
if ((pf->state & IXL_PF_STATE_RECOVERY_MODE) != 0) { | |||||
device_printf(dev, "Running in recovery mode, only firmware update available\n"); | |||||
return; | |||||
} | |||||
ixl_stop_locked(pf); | ixl_stop_locked(pf); | ||||
/* | /* | ||||
* If the aq is dead here, it probably means something outside of the driver | * If the aq is dead here, it probably means something outside of the driver | ||||
* did something to the adapter, like a PF reset. | * did something to the adapter, like a PF reset. | ||||
* So rebuild the driver's state here if that occurs. | * So rebuild the driver's state here if that occurs. | ||||
*/ | */ | ||||
if (!i40e_check_asq_alive(&pf->hw)) { | if (!i40e_check_asq_alive(&pf->hw)) { | ||||
device_printf(dev, "Admin Queue is down; resetting...\n"); | device_printf(dev, "Admin Queue is down; resetting...\n"); | ||||
ixl_teardown_hw_structs(pf); | ixl_teardown_hw_structs(pf); | ||||
ixl_reset(pf); | ixl_reset(pf); | ||||
} | } | ||||
/* Get the latest mac address... User might use a LAA */ | /* Get the latest mac address... User might use a LAA */ | ||||
bcopy(IF_LLADDR(vsi->ifp), tmpaddr, | if (ixl_set_lla(vsi)) { | ||||
ETH_ALEN); | device_printf(dev, "LLA address change failed!\n"); | ||||
if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && | |||||
(i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { | |||||
device_printf(dev, "ixl_init_locked: reconfigure MAC addr\n"); | |||||
ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); | |||||
bcopy(tmpaddr, hw->mac.addr, | |||||
ETH_ALEN); | |||||
ret = i40e_aq_mac_address_write(hw, | |||||
I40E_AQC_WRITE_TYPE_LAA_ONLY, | |||||
hw->mac.addr, NULL); | |||||
if (ret) { | |||||
device_printf(dev, "LLA address" | |||||
"change failed!!\n"); | |||||
return; | return; | ||||
} | } | ||||
} | |||||
ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); | |||||
/* Set the various hardware offload abilities */ | /* Set the various hardware offload abilities */ | ||||
ifp->if_hwassist = 0; | ifp->if_hwassist = 0; | ||||
if (ifp->if_capenable & IFCAP_TSO) | if (ifp->if_capenable & IFCAP_TSO) | ||||
ifp->if_hwassist |= CSUM_TSO; | ifp->if_hwassist |= CSUM_TSO; | ||||
if (ifp->if_capenable & IFCAP_TXCSUM) | if (ifp->if_capenable & IFCAP_TXCSUM) | ||||
ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); | ||||
if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) | if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) | ||||
ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); | ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); | ||||
Show All 11 Lines | ixl_init_locked(struct ixl_pf *pf) | ||||
if (ixl_initialize_vsi(vsi)) { | if (ixl_initialize_vsi(vsi)) { | ||||
device_printf(dev, "initialize vsi failed!!\n"); | device_printf(dev, "initialize vsi failed!!\n"); | ||||
return; | return; | ||||
} | } | ||||
/* Set up RSS */ | /* Set up RSS */ | ||||
ixl_config_rss(pf); | ixl_config_rss(pf); | ||||
/* Add protocol filters to list */ | |||||
ixl_init_filters(vsi); | |||||
/* Setup vlan's if needed */ | |||||
ixl_setup_vlan_filters(vsi); | |||||
/* Set up MSI/X routing and the ITR settings */ | /* Set up MSI/X routing and the ITR settings */ | ||||
if (pf->msix > 1) { | if (pf->msix > 1) { | ||||
ixl_configure_queue_intr_msix(pf); | ixl_configure_queue_intr_msix(pf); | ||||
ixl_configure_itr(pf); | ixl_configure_itr(pf); | ||||
} else | } else | ||||
ixl_configure_legacy(pf); | ixl_configure_legacy(pf); | ||||
ixl_enable_rings(vsi); | ixl_enable_rings(vsi); | ||||
i40e_aq_set_default_vsi(hw, vsi->seid, NULL); | i40e_aq_set_default_vsi(hw, vsi->seid, NULL); | ||||
ixl_reconfigure_filters(vsi); | ixl_reconfigure_filters(vsi); | ||||
/* Check if PROMISC or ALLMULTI flags have been set | |||||
* by user before bringing interface up */ | |||||
ixl_set_promisc(vsi); | |||||
/* And now turn on interrupts */ | /* And now turn on interrupts */ | ||||
ixl_enable_intr(vsi); | ixl_enable_intr(vsi); | ||||
/* Get link info */ | /* Get link info */ | ||||
hw->phy.get_link_info = TRUE; | hw->phy.get_link_info = TRUE; | ||||
i40e_get_link_status(hw, &pf->link_up); | i40e_get_link_status(hw, &pf->link_up); | ||||
ixl_update_link_status(pf); | ixl_update_link_status(pf); | ||||
/* Start the local timer */ | |||||
callout_reset(&pf->timer, hz, ixl_local_timer, pf); | |||||
/* Now inform the stack we're ready */ | /* Now inform the stack we're ready */ | ||||
ifp->if_drv_flags |= IFF_DRV_RUNNING; | ifp->if_drv_flags |= IFF_DRV_RUNNING; | ||||
#ifdef IXL_IW | #ifdef IXL_IW | ||||
if (ixl_enable_iwarp && pf->iw_enabled) { | if (ixl_enable_iwarp && pf->iw_enabled) { | ||||
ret = ixl_iw_pf_init(pf); | int ret = ixl_iw_pf_init(pf); | ||||
if (ret) | if (ret) | ||||
device_printf(dev, | device_printf(dev, | ||||
"initialize iwarp failed, code %d\n", ret); | "initialize iwarp failed, code %d\n", ret); | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* Get the hardware capabilities | * Get the hardware capabilities | ||||
* | * | ||||
**********************************************************************/ | **********************************************************************/ | ||||
int | int | ||||
ixl_get_hw_capabilities(struct ixl_pf *pf) | ixl_get_hw_capabilities(struct ixl_pf *pf) | ||||
{ | { | ||||
struct i40e_aqc_list_capabilities_element_resp *buf; | struct i40e_aqc_list_capabilities_element_resp *buf; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
int error, len; | int error, len, i2c_intfc_num; | ||||
u16 needed; | u16 needed; | ||||
bool again = TRUE; | bool again = TRUE; | ||||
if ((pf->state & IXL_PF_STATE_RECOVERY_MODE) != 0) { | |||||
hw->func_caps.iwarp = 0; | |||||
return 0; | |||||
} | |||||
len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); | len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp); | ||||
retry: | retry: | ||||
if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) | if (!(buf = (struct i40e_aqc_list_capabilities_element_resp *) | ||||
malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { | malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO))) { | ||||
device_printf(dev, "Unable to allocate cap memory\n"); | device_printf(dev, "Unable to allocate cap memory\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
/* This populates the hw struct */ | /* This populates the hw struct */ | ||||
error = i40e_aq_discover_capabilities(hw, buf, len, | error = i40e_aq_discover_capabilities(hw, buf, len, | ||||
&needed, i40e_aqc_opc_list_func_capabilities, NULL); | &needed, i40e_aqc_opc_list_func_capabilities, NULL); | ||||
free(buf, M_DEVBUF); | free(buf, M_DEVBUF); | ||||
if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && | if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) && | ||||
(again == TRUE)) { | (again == TRUE)) { | ||||
/* retry once with a larger buffer */ | /* retry once with a larger buffer */ | ||||
again = FALSE; | again = FALSE; | ||||
len = needed; | len = needed; | ||||
goto retry; | goto retry; | ||||
} else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { | } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { | ||||
device_printf(dev, "capability discovery failed: %d\n", | device_printf(dev, "capability discovery failed: %d\n", | ||||
pf->hw.aq.asq_last_status); | pf->hw.aq.asq_last_status); | ||||
return (ENODEV); | return (ENODEV); | ||||
} | } | ||||
/* Capture this PF's starting queue pair */ | |||||
pf->qbase = hw->func_caps.base_queue; | |||||
#ifdef IXL_DEBUG | #ifdef IXL_DEBUG | ||||
device_printf(dev, "pf_id=%d, num_vfs=%d, msix_pf=%d, " | device_printf(dev, "pf_id=%d, num_vfs=%d, msix_pf=%d, " | ||||
"msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", | "msix_vf=%d, fd_g=%d, fd_b=%d, tx_qp=%d rx_qp=%d qbase=%d\n", | ||||
hw->pf_id, hw->func_caps.num_vfs, | hw->pf_id, hw->func_caps.num_vfs, | ||||
hw->func_caps.num_msix_vectors, | hw->func_caps.num_msix_vectors, | ||||
hw->func_caps.num_msix_vectors_vf, | hw->func_caps.num_msix_vectors_vf, | ||||
hw->func_caps.fd_filters_guaranteed, | hw->func_caps.fd_filters_guaranteed, | ||||
hw->func_caps.fd_filters_best_effort, | hw->func_caps.fd_filters_best_effort, | ||||
hw->func_caps.num_tx_qp, | hw->func_caps.num_tx_qp, | ||||
hw->func_caps.num_rx_qp, | hw->func_caps.num_rx_qp, | ||||
hw->func_caps.base_queue); | hw->func_caps.base_queue); | ||||
#endif | #endif | ||||
struct i40e_osdep *osdep = (struct i40e_osdep *)hw->back; | /* | ||||
osdep->i2c_intfc_num = ixl_find_i2c_interface(pf); | * Some devices have both MDIO and I2C; since this isn't reported | ||||
if (osdep->i2c_intfc_num != -1) | * by the FW, check registers to see if an I2C interface exists. | ||||
*/ | |||||
i2c_intfc_num = ixl_find_i2c_interface(pf); | |||||
if (i2c_intfc_num != -1) | |||||
pf->has_i2c = true; | pf->has_i2c = true; | ||||
/* Determine functions to use for driver I2C accesses */ | |||||
switch (pf->i2c_access_method) { | |||||
case IXL_I2C_ACCESS_METHOD_BEST_AVAILABLE: { | |||||
if (hw->mac.type == I40E_MAC_XL710 && | |||||
hw->aq.api_maj_ver == 1 && | |||||
hw->aq.api_min_ver >= 7) { | |||||
pf->read_i2c_byte = ixl_read_i2c_byte_aq; | |||||
pf->write_i2c_byte = ixl_write_i2c_byte_aq; | |||||
} else { | |||||
pf->read_i2c_byte = ixl_read_i2c_byte_reg; | |||||
pf->write_i2c_byte = ixl_write_i2c_byte_reg; | |||||
} | |||||
break; | |||||
} | |||||
case IXL_I2C_ACCESS_METHOD_AQ: | |||||
pf->read_i2c_byte = ixl_read_i2c_byte_aq; | |||||
pf->write_i2c_byte = ixl_write_i2c_byte_aq; | |||||
break; | |||||
case IXL_I2C_ACCESS_METHOD_REGISTER_I2CCMD: | |||||
pf->read_i2c_byte = ixl_read_i2c_byte_reg; | |||||
pf->write_i2c_byte = ixl_write_i2c_byte_reg; | |||||
break; | |||||
case IXL_I2C_ACCESS_METHOD_BIT_BANG_I2CPARAMS: | |||||
pf->read_i2c_byte = ixl_read_i2c_byte_bb; | |||||
pf->write_i2c_byte = ixl_write_i2c_byte_bb; | |||||
break; | |||||
default: | |||||
/* Should not happen */ | |||||
device_printf(dev, "Error setting I2C access functions\n"); | |||||
break; | |||||
} | |||||
/* Print a subset of the capability information. */ | /* Print a subset of the capability information. */ | ||||
device_printf(dev, "PF-ID[%d]: VFs %d, MSIX %d, VF MSIX %d, QPs %d, %s\n", | device_printf(dev, "PF-ID[%d]: VFs %d, MSIX %d, VF MSIX %d, QPs %d, %s\n", | ||||
hw->pf_id, hw->func_caps.num_vfs, hw->func_caps.num_msix_vectors, | hw->pf_id, hw->func_caps.num_vfs, hw->func_caps.num_msix_vectors, | ||||
hw->func_caps.num_msix_vectors_vf, hw->func_caps.num_tx_qp, | hw->func_caps.num_msix_vectors_vf, hw->func_caps.num_tx_qp, | ||||
(hw->func_caps.mdio_port_mode == 2) ? "I2C" : | (hw->func_caps.mdio_port_mode == 2) ? "I2C" : | ||||
(hw->func_caps.mdio_port_mode == 1 && pf->has_i2c) ? "MDIO & I2C" : | (hw->func_caps.mdio_port_mode == 1 && pf->has_i2c) ? "MDIO & I2C" : | ||||
(hw->func_caps.mdio_port_mode == 1) ? "MDIO dedicated" : | (hw->func_caps.mdio_port_mode == 1) ? "MDIO dedicated" : | ||||
"MDIO shared"); | "MDIO shared"); | ||||
▲ Show 20 Lines • Show All 271 Lines • ▼ Show 20 Lines | ixl_intr(void *arg) | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
struct ixl_queue *que = vsi->queues; | struct ixl_queue *que = vsi->queues; | ||||
struct ifnet *ifp = vsi->ifp; | struct ifnet *ifp = vsi->ifp; | ||||
struct tx_ring *txr = &que->txr; | struct tx_ring *txr = &que->txr; | ||||
u32 icr0; | u32 icr0; | ||||
bool more; | bool more; | ||||
ixl_disable_intr0(hw); | |||||
pf->admin_irq++; | pf->admin_irq++; | ||||
/* Clear PBA at start of ISR if using legacy interrupts */ | /* Clear PBA at start of ISR if using legacy interrupts */ | ||||
if (pf->msix == 0) | if (pf->msix == 0) | ||||
wr32(hw, I40E_PFINT_DYN_CTL0, | wr32(hw, I40E_PFINT_DYN_CTL0, | ||||
I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | | I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | | ||||
(IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT)); | (IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT)); | ||||
Show All 40 Lines | ixl_msix_que(void *arg) | ||||
struct i40e_hw *hw = vsi->hw; | struct i40e_hw *hw = vsi->hw; | ||||
struct tx_ring *txr = &que->txr; | struct tx_ring *txr = &que->txr; | ||||
bool more_tx, more_rx; | bool more_tx, more_rx; | ||||
/* Protect against spurious interrupts */ | /* Protect against spurious interrupts */ | ||||
if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) | if (!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING)) | ||||
return; | return; | ||||
/* There are drivers which disable auto-masking of interrupts, | |||||
* which is a global setting for all ports. We have to make sure | |||||
* to mask it to not lose IRQs */ | |||||
ixl_disable_queue(hw, que->me); | |||||
++que->irqs; | ++que->irqs; | ||||
more_rx = ixl_rxeof(que, IXL_RX_LIMIT); | more_rx = ixl_rxeof(que, IXL_RX_LIMIT); | ||||
IXL_TX_LOCK(txr); | IXL_TX_LOCK(txr); | ||||
more_tx = ixl_txeof(que); | more_tx = ixl_txeof(que); | ||||
/* | /* | ||||
** Make certain that if the stack | ** Make certain that if the stack | ||||
▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | |||||
* Filter Routines | * Filter Routines | ||||
* | * | ||||
* Routines for multicast and vlan filter management. | * Routines for multicast and vlan filter management. | ||||
* | * | ||||
*********************************************************************/ | *********************************************************************/ | ||||
void | void | ||||
ixl_add_multi(struct ixl_vsi *vsi) | ixl_add_multi(struct ixl_vsi *vsi) | ||||
{ | { | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
struct ifnet *ifp = vsi->ifp; | struct ifnet *ifp = vsi->ifp; | ||||
struct i40e_hw *hw = vsi->hw; | struct i40e_hw *hw = vsi->hw; | ||||
int mcnt = 0, flags; | int mcnt = 0, flags; | ||||
IOCTL_DEBUGOUT("ixl_add_multi: begin"); | IOCTL_DEBUGOUT("ixl_add_multi: begin"); | ||||
if_maddr_rlock(ifp); | if_maddr_rlock(ifp); | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* Timer routine | * Timer routine | ||||
* | * | ||||
* This routine checks for link status, updates statistics, | * This routine checks for link status, updates statistics, | ||||
* and runs the watchdog check. | * and runs the watchdog check. | ||||
* | * | ||||
* Only runs when the driver is configured UP and RUNNING. | |||||
* | |||||
**********************************************************************/ | **********************************************************************/ | ||||
void | void | ||||
ixl_local_timer(void *arg) | ixl_local_timer(void *arg) | ||||
{ | { | ||||
struct ixl_pf *pf = arg; | struct ixl_pf *pf = arg; | ||||
struct ifnet *ifp = pf->vsi.ifp; | |||||
if (ixl_fw_recovery_mode(pf)) { | |||||
if (!(atomic_load_acq_int(&pf->state) & IXL_PF_STATE_RECOVERY_MODE)) { | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) | |||||
ixl_stop_locked(pf); | |||||
atomic_set_int(&pf->state, IXL_PF_STATE_RECOVERY_MODE | IXL_PF_STATE_EMPR_RESETTING); | |||||
device_printf(pf->dev, "Firmware recovery mode detected. Limiting functionality. Refer to Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n"); | |||||
} | |||||
} | |||||
IXL_PF_LOCK_ASSERT(pf); | IXL_PF_LOCK_ASSERT(pf); | ||||
/* Fire off the adminq task */ | /* Fire off the adminq task */ | ||||
taskqueue_enqueue(pf->tq, &pf->adminq); | taskqueue_enqueue(pf->tq, &pf->adminq); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | |||||
/* Update stats */ | /* Update stats */ | ||||
ixl_update_stats_counters(pf); | ixl_update_stats_counters(pf); | ||||
} | |||||
if (ixl_queue_hang_check(&pf->vsi)) { | |||||
/* Increment stat when a queue shows hung */ | /* Increment stat when a queue shows hung */ | ||||
if (ixl_queue_hang_check(&pf->vsi)) | |||||
pf->watchdog_events++; | pf->watchdog_events++; | ||||
} | |||||
callout_reset(&pf->timer, hz, ixl_local_timer, pf); | callout_reset(&pf->timer, hz, ixl_local_timer, pf); | ||||
} | } | ||||
void | void | ||||
ixl_link_up_msg(struct ixl_pf *pf) | ixl_link_up_msg(struct ixl_pf *pf) | ||||
{ | { | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
Show All 14 Lines | if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_RS_ENA) | ||||
neg_fec_string = ixl_fec_string[0]; | neg_fec_string = ixl_fec_string[0]; | ||||
else if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_KR_ENA) | else if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_KR_ENA) | ||||
neg_fec_string = ixl_fec_string[1]; | neg_fec_string = ixl_fec_string[1]; | ||||
else | else | ||||
neg_fec_string = ixl_fec_string[2]; | neg_fec_string = ixl_fec_string[2]; | ||||
log(LOG_NOTICE, "%s: Link is up, %s Full Duplex, Requested FEC: %s, Negotiated FEC: %s, Autoneg: %s, Flow Control: %s\n", | log(LOG_NOTICE, "%s: Link is up, %s Full Duplex, Requested FEC: %s, Negotiated FEC: %s, Autoneg: %s, Flow Control: %s\n", | ||||
ifp->if_xname, | ifp->if_xname, | ||||
ixl_aq_speed_to_str(hw->phy.link_info.link_speed), | ixl_link_speed_string(hw->phy.link_info.link_speed), | ||||
req_fec_string, neg_fec_string, | req_fec_string, neg_fec_string, | ||||
(hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) ? "True" : "False", | (hw->phy.link_info.an_info & I40E_AQ_AN_COMPLETED) ? "True" : "False", | ||||
(hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX && | (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX && | ||||
hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) ? | hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) ? | ||||
ixl_fc_string[3] : (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) ? | ixl_fc_string[3] : (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) ? | ||||
ixl_fc_string[2] : (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) ? | ixl_fc_string[2] : (hw->phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) ? | ||||
ixl_fc_string[1] : ixl_fc_string[0]); | ixl_fc_string[1] : ixl_fc_string[0]); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
struct ifnet *ifp = vsi->ifp; | struct ifnet *ifp = vsi->ifp; | ||||
INIT_DEBUGOUT("ixl_stop: begin\n"); | INIT_DEBUGOUT("ixl_stop: begin\n"); | ||||
IXL_PF_LOCK_ASSERT(pf); | IXL_PF_LOCK_ASSERT(pf); | ||||
/* Tell the stack that the interface is no longer active */ | |||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING); | |||||
#ifdef IXL_IW | #ifdef IXL_IW | ||||
/* Stop iWARP device */ | /* Stop iWARP device */ | ||||
if (ixl_enable_iwarp && pf->iw_enabled) | if (ixl_enable_iwarp && pf->iw_enabled) | ||||
ixl_iw_pf_stop(pf); | ixl_iw_pf_stop(pf); | ||||
#endif | #endif | ||||
/* Stop the local timer */ | |||||
callout_stop(&pf->timer); | |||||
ixl_disable_rings_intr(vsi); | ixl_disable_rings_intr(vsi); | ||||
ixl_disable_rings(vsi); | ixl_disable_rings(vsi); | ||||
/* Tell the stack that the interface is no longer active */ | |||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING); | |||||
} | } | ||||
void | void | ||||
ixl_stop(struct ixl_pf *pf) | ixl_stop(struct ixl_pf *pf) | ||||
{ | { | ||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
ixl_stop_locked(pf); | ixl_stop_locked(pf); | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
▲ Show 20 Lines • Show All 668 Lines • ▼ Show 20 Lines | ixl_add_ifmedia(struct ixl_vsi *vsi, u64 phy_types) | ||||
if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_T)) | if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_T)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL); | ||||
if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_SX)) | if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_SX)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_SX, 0, NULL); | ||||
if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_LX)) | if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_LX)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_LX, 0, NULL); | ||||
if (phy_types & (I40E_CAP_PHY_TYPE_2_5GBASE_T)) | |||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_2500_T, 0, NULL); | |||||
if (phy_types & (I40E_CAP_PHY_TYPE_5GBASE_T)) | |||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_5000_T, 0, NULL); | |||||
if (phy_types & (I40E_CAP_PHY_TYPE_XAUI) || | if (phy_types & (I40E_CAP_PHY_TYPE_XAUI) || | ||||
phy_types & (I40E_CAP_PHY_TYPE_XFI) || | phy_types & (I40E_CAP_PHY_TYPE_XFI) || | ||||
phy_types & (I40E_CAP_PHY_TYPE_10GBASE_SFPP_CU)) | phy_types & (I40E_CAP_PHY_TYPE_10GBASE_SFPP_CU)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL); | ||||
if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_SR)) | if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_SR)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL); | ||||
if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_LR)) | if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_LR)) | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | ixl_setup_interface(device_t dev, struct ixl_vsi *vsi) | ||||
struct i40e_aq_get_phy_abilities_resp abilities; | struct i40e_aq_get_phy_abilities_resp abilities; | ||||
enum i40e_status_code aq_error = 0; | enum i40e_status_code aq_error = 0; | ||||
INIT_DEBUGOUT("ixl_setup_interface: begin"); | INIT_DEBUGOUT("ixl_setup_interface: begin"); | ||||
ifp = vsi->ifp = if_alloc(IFT_ETHER); | ifp = vsi->ifp = if_alloc(IFT_ETHER); | ||||
if (ifp == NULL) { | if (ifp == NULL) { | ||||
device_printf(dev, "can not allocate ifnet structure\n"); | device_printf(dev, "can not allocate ifnet structure\n"); | ||||
return (-1); | return (ENOMEM); | ||||
} | } | ||||
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | if_initname(ifp, device_get_name(dev), device_get_unit(dev)); | ||||
ifp->if_mtu = ETHERMTU; | ifp->if_mtu = ETHERMTU; | ||||
ifp->if_init = ixl_init; | ifp->if_init = ixl_init; | ||||
ifp->if_softc = vsi; | ifp->if_softc = vsi; | ||||
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | ||||
ifp->if_ioctl = ixl_ioctl; | ifp->if_ioctl = ixl_ioctl; | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Specify the media types supported by this adapter and register | * Specify the media types supported by this adapter and register | ||||
* callbacks to update media and link information | * callbacks to update media and link information | ||||
*/ | */ | ||||
ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, | ifmedia_init(&vsi->media, IFM_IMASK, ixl_media_change, | ||||
ixl_media_status); | ixl_media_status); | ||||
if ((atomic_load_acq_int(&pf->state) & IXL_PF_STATE_RECOVERY_MODE) == 0) { | |||||
aq_error = i40e_aq_get_phy_capabilities(hw, | aq_error = i40e_aq_get_phy_capabilities(hw, | ||||
FALSE, TRUE, &abilities, NULL); | FALSE, TRUE, &abilities, NULL); | ||||
/* May need delay to detect fiber correctly */ | /* May need delay to detect fiber correctly */ | ||||
if (aq_error == I40E_ERR_UNKNOWN_PHY) { | if (aq_error == I40E_ERR_UNKNOWN_PHY) { | ||||
i40e_msec_delay(200); | i40e_msec_delay(200); | ||||
aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, | aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, | ||||
TRUE, &abilities, NULL); | TRUE, &abilities, NULL); | ||||
} | } | ||||
if (aq_error) { | if (aq_error) { | ||||
if (aq_error == I40E_ERR_UNKNOWN_PHY) | if (aq_error == I40E_ERR_UNKNOWN_PHY) | ||||
device_printf(dev, "Unknown PHY type detected!\n"); | device_printf(dev, "Unknown PHY type detected!\n"); | ||||
else | else | ||||
device_printf(dev, | device_printf(dev, | ||||
"Error getting supported media types, err %d," | "Error getting supported media types, err %d," | ||||
" AQ error %d\n", aq_error, hw->aq.asq_last_status); | " AQ error %d\n", aq_error, hw->aq.asq_last_status); | ||||
} else { | } else { | ||||
pf->supported_speeds = abilities.link_speed; | pf->supported_speeds = abilities.link_speed; | ||||
#if __FreeBSD_version >= 1100000 | #if __FreeBSD_version >= 1100000 | ||||
ifp->if_baudrate = ixl_max_aq_speed_to_value(pf->supported_speeds); | ifp->if_baudrate = ixl_max_aq_speed_to_value(pf->supported_speeds); | ||||
#else | #else | ||||
if_initbaudrate(ifp, ixl_max_aq_speed_to_value(pf->supported_speeds)); | if_initbaudrate(ifp, ixl_max_aq_speed_to_value(pf->supported_speeds)); | ||||
#endif | #endif | ||||
ixl_add_ifmedia(vsi, hw->phy.phy_types); | ixl_add_ifmedia(vsi, hw->phy.phy_types); | ||||
} | } | ||||
} | |||||
/* Use autoselect media by default */ | /* Use autoselect media by default */ | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL); | ||||
ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); | ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO); | ||||
ether_ifattach(ifp, hw->mac.addr); | ether_ifattach(ifp, hw->mac.addr); | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | #ifdef IXL_IW | ||||
} | } | ||||
#endif | #endif | ||||
/* Save VSI number and info for use later */ | /* Save VSI number and info for use later */ | ||||
vsi->vsi_num = ctxt.vsi_number; | vsi->vsi_num = ctxt.vsi_number; | ||||
bcopy(&ctxt.info, &vsi->info, sizeof(vsi->info)); | bcopy(&ctxt.info, &vsi->info, sizeof(vsi->info)); | ||||
/* Reset VSI statistics */ | /* Reset VSI statistics */ | ||||
ixl_vsi_reset_stats(vsi); | ixl_vsi_reset_stats(vsi); | ||||
vsi->hw_filters_add = 0; | |||||
vsi->hw_filters_del = 0; | |||||
ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF); | ctxt.flags = htole16(I40E_AQ_VSI_TYPE_PF); | ||||
err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); | err = i40e_aq_update_vsi_params(hw, &ctxt, NULL); | ||||
if (err) { | if (err) { | ||||
device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d," | device_printf(dev, "i40e_aq_update_vsi_params() failed, error %d," | ||||
" aq_error %d\n", err, hw->aq.asq_last_status); | " aq_error %d\n", err, hw->aq.asq_last_status); | ||||
return (err); | return (err); | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | if (vsi->ifp->if_capenable & IFCAP_NETMAP) { | ||||
wr32(vsi->hw, I40E_QRX_TAIL(que->me), t); | wr32(vsi->hw, I40E_QRX_TAIL(que->me), t); | ||||
} else | } else | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_rx_desc - 1); | wr32(vsi->hw, I40E_QRX_TAIL(que->me), que->num_rx_desc - 1); | ||||
} | } | ||||
return (err); | return (err); | ||||
} | } | ||||
void | void | ||||
ixl_vsi_free_queues(struct ixl_vsi *vsi) | ixl_vsi_free_queues(struct ixl_vsi *vsi) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)vsi->back; | struct ixl_pf *pf = (struct ixl_pf *)vsi->back; | ||||
struct ixl_queue *que = vsi->queues; | struct ixl_queue *que = vsi->queues; | ||||
if (NULL == vsi->queues) | if (NULL == vsi->queues) | ||||
return; | return; | ||||
Show All 17 Lines | if (!mtx_initialized(&rxr->mtx)) /* uninitialized */ | ||||
continue; | continue; | ||||
IXL_RX_LOCK(rxr); | IXL_RX_LOCK(rxr); | ||||
ixl_free_que_rx(que); | ixl_free_que_rx(que); | ||||
if (rxr->base) | if (rxr->base) | ||||
i40e_free_dma_mem(&pf->hw, &rxr->dma); | i40e_free_dma_mem(&pf->hw, &rxr->dma); | ||||
IXL_RX_UNLOCK(rxr); | IXL_RX_UNLOCK(rxr); | ||||
IXL_RX_LOCK_DESTROY(rxr); | IXL_RX_LOCK_DESTROY(rxr); | ||||
} | } | ||||
sysctl_ctx_free(&vsi->sysctl_ctx); | |||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* Free all VSI structs. | * Free all VSI structs. | ||||
* | * | ||||
**********************************************************************/ | **********************************************************************/ | ||||
void | void | ||||
ixl_free_vsi(struct ixl_vsi *vsi) | ixl_free_vsi(struct ixl_vsi *vsi) | ||||
{ | { | ||||
/* Free station queues */ | /* Free station queues */ | ||||
ixl_vsi_free_queues(vsi); | ixl_vsi_free_queues(vsi); | ||||
if (vsi->queues) | if (vsi->queues) | ||||
free(vsi->queues, M_DEVBUF); | free(vsi->queues, M_DEVBUF); | ||||
/* Free VSI filter list */ | /* Free VSI filter list */ | ||||
ixl_free_mac_filters(vsi); | ixl_free_mac_filters(vsi); | ||||
} | } | ||||
void | void | ||||
ixl_free_mac_filters(struct ixl_vsi *vsi) | ixl_free_mac_filters(struct ixl_vsi *vsi) | ||||
{ | { | ||||
struct ixl_mac_filter *f; | struct ixl_mac_filter *f; | ||||
while (!SLIST_EMPTY(&vsi->ftl)) { | while (!SLIST_EMPTY(&vsi->ftl)) { | ||||
f = SLIST_FIRST(&vsi->ftl); | f = SLIST_FIRST(&vsi->ftl); | ||||
SLIST_REMOVE_HEAD(&vsi->ftl, next); | SLIST_REMOVE_HEAD(&vsi->ftl, next); | ||||
free(f, M_DEVBUF); | free(f, M_DEVBUF); | ||||
} | } | ||||
vsi->num_hw_filters = 0; | |||||
} | } | ||||
/* | /* | ||||
* Fill out fields in queue struct and setup tx/rx memory and structs | * Fill out fields in queue struct and setup tx/rx memory and structs | ||||
*/ | */ | ||||
static int | static int | ||||
ixl_vsi_setup_queue(struct ixl_vsi *vsi, struct ixl_queue *que, int index) | ixl_vsi_setup_queue(struct ixl_vsi *vsi, struct ixl_queue *que, int index) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | ixl_vsi_setup_queues(struct ixl_vsi *vsi) | ||||
int error = 0; | int error = 0; | ||||
for (int i = 0; i < vsi->num_queues; i++) { | for (int i = 0; i < vsi->num_queues; i++) { | ||||
que = &vsi->queues[i]; | que = &vsi->queues[i]; | ||||
error = ixl_vsi_setup_queue(vsi, que, i); | error = ixl_vsi_setup_queue(vsi, que, i); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
} | } | ||||
if (error == 0) | |||||
sysctl_ctx_init(&vsi->sysctl_ctx); | |||||
return (error); | return (error); | ||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* Allocate memory for the VSI (virtual station interface) and their | * Allocate memory for the VSI (virtual station interface) and their | ||||
* associated queues, rings and the descriptors associated with each, | * associated queues, rings and the descriptors associated with each, | ||||
▲ Show 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | if (pf->dynamic_tx_itr) { | ||||
} | } | ||||
} | } | ||||
txr->bytes = 0; | txr->bytes = 0; | ||||
txr->packets = 0; | txr->packets = 0; | ||||
return; | return; | ||||
} | } | ||||
void | void | ||||
ixl_add_vsi_sysctls(struct ixl_pf *pf, struct ixl_vsi *vsi, | ixl_vsi_add_sysctls(struct ixl_vsi * vsi, const char * sysctl_name, bool queues_sysctls) | ||||
struct sysctl_ctx_list *ctx, const char *sysctl_name) | |||||
{ | { | ||||
struct sysctl_oid *tree; | struct sysctl_oid *tree; | ||||
struct sysctl_oid_list *child; | struct sysctl_oid_list *child; | ||||
struct sysctl_oid_list *vsi_list; | struct sysctl_oid_list *vsi_list; | ||||
tree = device_get_sysctl_tree(pf->dev); | tree = device_get_sysctl_tree(vsi->dev); | ||||
child = SYSCTL_CHILDREN(tree); | child = SYSCTL_CHILDREN(tree); | ||||
vsi->vsi_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, sysctl_name, | vsi->vsi_node = SYSCTL_ADD_NODE(&vsi->sysctl_ctx, child, OID_AUTO, sysctl_name, | ||||
CTLFLAG_RD, NULL, "VSI Number"); | CTLFLAG_RD, NULL, "VSI Number"); | ||||
vsi_list = SYSCTL_CHILDREN(vsi->vsi_node); | vsi_list = SYSCTL_CHILDREN(vsi->vsi_node); | ||||
ixl_add_sysctls_eth_stats(&vsi->sysctl_ctx, vsi_list, &vsi->eth_stats); | |||||
ixl_add_sysctls_eth_stats(ctx, vsi_list, &vsi->eth_stats); | if (queues_sysctls) | ||||
ixl_vsi_add_queues_stats(vsi); | |||||
} | } | ||||
#ifdef IXL_DEBUG | |||||
/** | |||||
* ixl_sysctl_qtx_tail_handler | |||||
* Retrieves I40E_QTX_TAIL value from hardware | |||||
* for a sysctl. | |||||
*/ | |||||
static int | |||||
ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_queue *que; | |||||
int error; | |||||
u32 val; | |||||
que = ((struct ixl_queue *)oidp->oid_arg1); | |||||
if (!que) return 0; | |||||
val = rd32(que->vsi->hw, que->txr.tail); | |||||
error = sysctl_handle_int(oidp, &val, 0, req); | |||||
if (error || !req->newptr) | |||||
return error; | |||||
return (0); | |||||
} | |||||
/** | |||||
* ixl_sysctl_qrx_tail_handler | |||||
* Retrieves I40E_QRX_TAIL value from hardware | |||||
* for a sysctl. | |||||
*/ | |||||
static int | |||||
ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_queue *que; | |||||
int error; | |||||
u32 val; | |||||
que = ((struct ixl_queue *)oidp->oid_arg1); | |||||
if (!que) return 0; | |||||
val = rd32(que->vsi->hw, que->rxr.tail); | |||||
error = sysctl_handle_int(oidp, &val, 0, req); | |||||
if (error || !req->newptr) | |||||
return error; | |||||
return (0); | |||||
} | |||||
#endif | |||||
/* | /* | ||||
* Used to set the Tx ITR value for all of the PF LAN VSI's queues. | * Used to set the Tx ITR value for all of the PF LAN VSI's queues. | ||||
* Writes to the ITR registers immediately. | * Writes to the ITR registers immediately. | ||||
*/ | */ | ||||
static int | static int | ||||
ixl_sysctl_pf_tx_itr(SYSCTL_HANDLER_ARGS) | ixl_sysctl_pf_tx_itr(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | struct ixl_pf *pf = (struct ixl_pf *)arg1; | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | ixl_sysctl_pf_rx_itr(SYSCTL_HANDLER_ARGS) | ||||
return (error); | return (error); | ||||
} | } | ||||
void | void | ||||
ixl_add_hw_stats(struct ixl_pf *pf) | ixl_add_hw_stats(struct ixl_pf *pf) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct ixl_vsi *vsi = &pf->vsi; | |||||
struct ixl_queue *queues = vsi->queues; | |||||
struct i40e_hw_port_stats *pf_stats = &pf->stats; | struct i40e_hw_port_stats *pf_stats = &pf->stats; | ||||
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); | struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); | ||||
struct sysctl_oid *tree = device_get_sysctl_tree(dev); | struct sysctl_oid *tree = device_get_sysctl_tree(dev); | ||||
struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); | struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); | ||||
struct sysctl_oid_list *vsi_list; | |||||
struct sysctl_oid *queue_node; | |||||
struct sysctl_oid_list *queue_list; | |||||
struct tx_ring *txr; | |||||
struct rx_ring *rxr; | |||||
char queue_namebuf[QUEUE_NAME_LEN]; | |||||
/* Driver statistics */ | /* Driver statistics */ | ||||
SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "watchdog_events", | SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "watchdog_events", | ||||
CTLFLAG_RD, &pf->watchdog_events, | CTLFLAG_RD, &pf->watchdog_events, | ||||
"Watchdog timeouts"); | "Watchdog timeouts"); | ||||
SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "admin_irq", | SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "admin_irq", | ||||
CTLFLAG_RD, &pf->admin_irq, | CTLFLAG_RD, &pf->admin_irq, | ||||
"Admin Queue IRQ Handled"); | "Admin Queue IRQ Handled"); | ||||
ixl_add_vsi_sysctls(pf, &pf->vsi, ctx, "pf"); | ixl_vsi_add_sysctls(&pf->vsi, "pf", true); | ||||
vsi_list = SYSCTL_CHILDREN(pf->vsi.vsi_node); | |||||
/* Queue statistics */ | |||||
for (int q = 0; q < vsi->num_queues; q++) { | |||||
snprintf(queue_namebuf, QUEUE_NAME_LEN, "que%d", q); | |||||
queue_node = SYSCTL_ADD_NODE(ctx, vsi_list, | |||||
OID_AUTO, queue_namebuf, CTLFLAG_RD, NULL, "Queue #"); | |||||
queue_list = SYSCTL_CHILDREN(queue_node); | |||||
txr = &(queues[q].txr); | |||||
rxr = &(queues[q].rxr); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mbuf_defrag_failed", | |||||
CTLFLAG_RD, &(queues[q].mbuf_defrag_failed), | |||||
"m_defrag() failed"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", | |||||
CTLFLAG_RD, &(queues[q].irqs), | |||||
"irqs on this queue"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", | |||||
CTLFLAG_RD, &(queues[q].tso), | |||||
"TSO"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dmamap_failed", | |||||
CTLFLAG_RD, &(queues[q].tx_dmamap_failed), | |||||
"Driver tx dma failure in xmit"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "mss_too_small", | |||||
CTLFLAG_RD, &(queues[q].mss_too_small), | |||||
"TSO sends with an MSS less than 64"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", | |||||
CTLFLAG_RD, &(txr->no_desc), | |||||
"Queue No Descriptor Available"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", | |||||
CTLFLAG_RD, &(txr->total_packets), | |||||
"Queue Packets Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", | |||||
CTLFLAG_RD, &(txr->tx_bytes), | |||||
"Queue Bytes Transmitted"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_packets", | |||||
CTLFLAG_RD, &(rxr->rx_packets), | |||||
"Queue Packets Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_bytes", | |||||
CTLFLAG_RD, &(rxr->rx_bytes), | |||||
"Queue Bytes Received"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_desc_err", | |||||
CTLFLAG_RD, &(rxr->desc_errs), | |||||
"Queue Rx Descriptor Errors"); | |||||
SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_itr", | |||||
CTLFLAG_RD, &(rxr->itr), 0, | |||||
"Queue Rx ITR Interval"); | |||||
SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "tx_itr", | |||||
CTLFLAG_RD, &(txr->itr), 0, | |||||
"Queue Tx ITR Interval"); | |||||
#ifdef IXL_DEBUG | |||||
SYSCTL_ADD_INT(ctx, queue_list, OID_AUTO, "txr_watchdog", | |||||
CTLFLAG_RD, &(txr->watchdog_timer), 0, | |||||
"Ticks before watchdog timer causes interface reinit"); | |||||
SYSCTL_ADD_U16(ctx, queue_list, OID_AUTO, "tx_next_avail", | |||||
CTLFLAG_RD, &(txr->next_avail), 0, | |||||
"Next TX descriptor to be used"); | |||||
SYSCTL_ADD_U16(ctx, queue_list, OID_AUTO, "tx_next_to_clean", | |||||
CTLFLAG_RD, &(txr->next_to_clean), 0, | |||||
"Next TX descriptor to be cleaned"); | |||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "rx_not_done", | |||||
CTLFLAG_RD, &(rxr->not_done), | |||||
"Queue Rx Descriptors not Done"); | |||||
SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_refresh", | |||||
CTLFLAG_RD, &(rxr->next_refresh), 0, | |||||
"Queue Rx Descriptors not Done"); | |||||
SYSCTL_ADD_UINT(ctx, queue_list, OID_AUTO, "rx_next_check", | |||||
CTLFLAG_RD, &(rxr->next_check), 0, | |||||
"Queue Rx Descriptors not Done"); | |||||
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qrx_tail", | |||||
CTLTYPE_UINT | CTLFLAG_RD, &queues[q], | |||||
sizeof(struct ixl_queue), | |||||
ixl_sysctl_qrx_tail_handler, "IU", | |||||
"Queue Receive Descriptor Tail"); | |||||
SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "qtx_tail", | |||||
CTLTYPE_UINT | CTLFLAG_RD, &queues[q], | |||||
sizeof(struct ixl_queue), | |||||
ixl_sysctl_qtx_tail_handler, "IU", | |||||
"Queue Transmit Descriptor Tail"); | |||||
#endif | |||||
} | |||||
/* MAC stats */ | /* MAC stats */ | ||||
ixl_add_sysctls_mac_stats(ctx, child, pf_stats); | ixl_add_sysctls_mac_stats(ctx, child, pf_stats); | ||||
} | } | ||||
void | void | ||||
ixl_add_sysctls_eth_stats(struct sysctl_ctx_list *ctx, | |||||
struct sysctl_oid_list *child, | |||||
struct i40e_eth_stats *eth_stats) | |||||
{ | |||||
struct ixl_sysctl_info ctls[] = | |||||
{ | |||||
{ð_stats->rx_bytes, "good_octets_rcvd", "Good Octets Received"}, | |||||
{ð_stats->rx_unicast, "ucast_pkts_rcvd", | |||||
"Unicast Packets Received"}, | |||||
{ð_stats->rx_multicast, "mcast_pkts_rcvd", | |||||
"Multicast Packets Received"}, | |||||
{ð_stats->rx_broadcast, "bcast_pkts_rcvd", | |||||
"Broadcast Packets Received"}, | |||||
{ð_stats->rx_discards, "rx_discards", "Discarded RX packets"}, | |||||
{ð_stats->tx_bytes, "good_octets_txd", "Good Octets Transmitted"}, | |||||
{ð_stats->tx_unicast, "ucast_pkts_txd", "Unicast Packets Transmitted"}, | |||||
{ð_stats->tx_multicast, "mcast_pkts_txd", | |||||
"Multicast Packets Transmitted"}, | |||||
{ð_stats->tx_broadcast, "bcast_pkts_txd", | |||||
"Broadcast Packets Transmitted"}, | |||||
// end | |||||
{0,0,0} | |||||
}; | |||||
struct ixl_sysctl_info *entry = ctls; | |||||
while (entry->stat != 0) | |||||
{ | |||||
SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, entry->name, | |||||
CTLFLAG_RD, entry->stat, | |||||
entry->description); | |||||
entry++; | |||||
} | |||||
} | |||||
void | |||||
ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, | ixl_add_sysctls_mac_stats(struct sysctl_ctx_list *ctx, | ||||
struct sysctl_oid_list *child, | struct sysctl_oid_list *child, | ||||
struct i40e_hw_port_stats *stats) | struct i40e_hw_port_stats *stats) | ||||
{ | { | ||||
struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", | struct sysctl_oid *stat_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "mac", | ||||
CTLFLAG_RD, NULL, "Mac Statistics"); | CTLFLAG_RD, NULL, "Mac Statistics"); | ||||
struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); | struct sysctl_oid_list *stat_list = SYSCTL_CHILDREN(stat_node); | ||||
▲ Show 20 Lines • Show All 219 Lines • ▼ Show 20 Lines | ixl_unregister_vlan(void *arg, struct ifnet *ifp, u16 vtag) | ||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
--vsi->num_vlans; | --vsi->num_vlans; | ||||
ixl_del_filter(vsi, hw->mac.addr, vtag); | ixl_del_filter(vsi, hw->mac.addr, vtag); | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
} | } | ||||
/* | /* | ||||
** This routine updates vlan filters, called by init | * In some firmware versions there is default MAC/VLAN filter | ||||
** it scans the filter table and then updates the hw | * configured which interferes with filters managed by driver. | ||||
** after a soft reset. | * Make sure it's removed. | ||||
*/ | */ | ||||
void | void | ||||
ixl_setup_vlan_filters(struct ixl_vsi *vsi) | ixl_del_default_hw_filters(struct ixl_vsi *vsi) | ||||
{ | { | ||||
struct ixl_mac_filter *f; | struct i40e_aqc_remove_macvlan_element_data e; | ||||
int cnt = 0, flags; | |||||
if (vsi->num_vlans == 0) | bzero(&e, sizeof(e)); | ||||
return; | bcopy(vsi->hw->mac.perm_addr, e.mac_addr, ETHER_ADDR_LEN); | ||||
/* | e.vlan_tag = 0; | ||||
** Scan the filter list for vlan entries, | e.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH; | ||||
** mark them for addition and then call | i40e_aq_remove_macvlan(vsi->hw, vsi->seid, &e, 1, NULL); | ||||
** for the AQ update. | |||||
*/ | bzero(&e, sizeof(e)); | ||||
SLIST_FOREACH(f, &vsi->ftl, next) { | bcopy(vsi->hw->mac.perm_addr, e.mac_addr, ETHER_ADDR_LEN); | ||||
if (f->flags & IXL_FILTER_VLAN) { | e.vlan_tag = 0; | ||||
f->flags |= | e.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH | | ||||
(IXL_FILTER_ADD | | I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; | ||||
IXL_FILTER_USED); | i40e_aq_remove_macvlan(vsi->hw, vsi->seid, &e, 1, NULL); | ||||
cnt++; | |||||
} | } | ||||
static enum i40e_status_code | |||||
ixl_set_lla(struct ixl_vsi *vsi) | |||||
{ | |||||
struct i40e_hw *hw = vsi->hw; | |||||
u8 tmpaddr[ETHER_ADDR_LEN]; | |||||
enum i40e_status_code status; | |||||
status = I40E_SUCCESS; | |||||
bcopy(IF_LLADDR(vsi->ifp), tmpaddr, ETHER_ADDR_LEN); | |||||
if (memcmp(hw->mac.addr, tmpaddr, ETHER_ADDR_LEN) == 0) | |||||
goto set_lla_exit; | |||||
status = i40e_validate_mac_addr(tmpaddr); | |||||
if (status != I40E_SUCCESS) | |||||
goto set_lla_exit; | |||||
ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); | |||||
bcopy(tmpaddr, hw->mac.addr, ETHER_ADDR_LEN); | |||||
status = i40e_aq_mac_address_write(hw, | |||||
I40E_AQC_WRITE_TYPE_LAA_ONLY, | |||||
hw->mac.addr, NULL); | |||||
if (status != I40E_SUCCESS) | |||||
goto set_lla_exit; | |||||
ixl_add_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); | |||||
set_lla_exit: | |||||
return (status); | |||||
} | } | ||||
if (cnt == 0) { | |||||
printf("setup vlan: no filters found!\n"); | |||||
return; | |||||
} | |||||
flags = IXL_FILTER_VLAN; | |||||
flags |= (IXL_FILTER_ADD | IXL_FILTER_USED); | |||||
ixl_add_hw_filters(vsi, flags, cnt); | |||||
return; | |||||
} | |||||
/* | /* | ||||
** Initialize filter list and add filters that the hardware | ** Initialize filter list and add filters that the hardware | ||||
** needs to know about. | ** needs to know about. | ||||
** | ** | ||||
** Requires VSI's filter list & seid to be set before calling. | ** Requires VSI's seid to be set before calling. | ||||
*/ | */ | ||||
void | void | ||||
ixl_init_filters(struct ixl_vsi *vsi) | ixl_init_filters(struct ixl_vsi *vsi) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)vsi->back; | struct ixl_pf *pf = (struct ixl_pf *)vsi->back; | ||||
/* Initialize mac filter list for VSI */ | |||||
SLIST_INIT(&vsi->ftl); | |||||
vsi->num_hw_filters = 0; | |||||
/* Add broadcast address */ | /* Add broadcast address */ | ||||
ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY); | ixl_add_filter(vsi, ixl_bcast_addr, IXL_VLAN_ANY); | ||||
if (IXL_VSI_IS_VF(vsi)) | |||||
return; | |||||
ixl_del_default_hw_filters(vsi); | |||||
ixl_add_filter(vsi, vsi->hw->mac.addr, IXL_VLAN_ANY); | |||||
/* | /* | ||||
* Prevent Tx flow control frames from being sent out by | * Prevent Tx flow control frames from being sent out by | ||||
* non-firmware transmitters. | * non-firmware transmitters. | ||||
* This affects every VSI in the PF. | * This affects every VSI in the PF. | ||||
*/ | */ | ||||
if (pf->enable_tx_fc_filter) | if (pf->enable_tx_fc_filter) | ||||
i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid); | i40e_add_filter_to_drop_tx_flow_control_frames(vsi->hw, vsi->seid); | ||||
} | } | ||||
Show All 22 Lines | f->flags |= (IXL_FILTER_ADD | IXL_FILTER_USED | ||||
| IXL_FILTER_MC); | | IXL_FILTER_MC); | ||||
return; | return; | ||||
} | } | ||||
void | void | ||||
ixl_reconfigure_filters(struct ixl_vsi *vsi) | ixl_reconfigure_filters(struct ixl_vsi *vsi) | ||||
{ | { | ||||
ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_macs); | ixl_add_hw_filters(vsi, IXL_FILTER_USED, vsi->num_hw_filters); | ||||
} | } | ||||
/* | /* | ||||
** This routine adds macvlan filters | ** This routine adds macvlan filters | ||||
*/ | */ | ||||
void | void | ||||
ixl_add_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan) | ixl_add_filter(struct ixl_vsi *vsi, const u8 *macaddr, s16 vlan) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | if (j == cnt) | ||||
break; | break; | ||||
} | } | ||||
if (j > 0) { | if (j > 0) { | ||||
err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); | err = i40e_aq_add_macvlan(hw, vsi->seid, a, j, NULL); | ||||
if (err) | if (err) | ||||
device_printf(dev, "aq_add_macvlan err %d, " | device_printf(dev, "aq_add_macvlan err %d, " | ||||
"aq_error %d\n", err, hw->aq.asq_last_status); | "aq_error %d\n", err, hw->aq.asq_last_status); | ||||
else | else | ||||
vsi->hw_filters_add += j; | vsi->num_hw_filters += j; | ||||
} | } | ||||
free(a, M_DEVBUF); | free(a, M_DEVBUF); | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
** This routine takes removals in the vsi filter | ** This routine takes removals in the vsi filter | ||||
** table and creates an Admin Queue call to delete | ** table and creates an Admin Queue call to delete | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | if (j == cnt) | ||||
break; | break; | ||||
} | } | ||||
if (j > 0) { | if (j > 0) { | ||||
err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); | err = i40e_aq_remove_macvlan(hw, vsi->seid, d, j, NULL); | ||||
if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { | if (err && hw->aq.asq_last_status != I40E_AQ_RC_ENOENT) { | ||||
int sc = 0; | int sc = 0; | ||||
for (int i = 0; i < j; i++) | for (int i = 0; i < j; i++) | ||||
sc += (!d[i].error_code); | sc += (!d[i].error_code); | ||||
vsi->hw_filters_del += sc; | vsi->num_hw_filters -= sc; | ||||
device_printf(dev, | device_printf(dev, | ||||
"Failed to remove %d/%d filters, aq error %d\n", | "Failed to remove %d/%d filters, aq error %d\n", | ||||
j - sc, j, hw->aq.asq_last_status); | j - sc, j, hw->aq.asq_last_status); | ||||
} else | } else | ||||
vsi->hw_filters_del += j; | vsi->num_hw_filters -= j; | ||||
} | } | ||||
free(d, M_DEVBUF); | free(d, M_DEVBUF); | ||||
DEBUGOUT("ixl_del_hw_filters: end\n"); | DEBUGOUT("ixl_del_hw_filters: end\n"); | ||||
return; | return; | ||||
} | } | ||||
int | int | ||||
▲ Show 20 Lines • Show All 486 Lines • ▼ Show 20 Lines | ixl_stat_update32(hw, I40E_GLPRT_RFC(hw->port), | ||||
pf->stat_offsets_loaded, | pf->stat_offsets_loaded, | ||||
&osd->rx_fragments, &nsd->rx_fragments); | &osd->rx_fragments, &nsd->rx_fragments); | ||||
ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), | ixl_stat_update32(hw, I40E_GLPRT_ROC(hw->port), | ||||
pf->stat_offsets_loaded, | pf->stat_offsets_loaded, | ||||
&osd->rx_oversize, &nsd->rx_oversize); | &osd->rx_oversize, &nsd->rx_oversize); | ||||
ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), | ixl_stat_update32(hw, I40E_GLPRT_RJC(hw->port), | ||||
pf->stat_offsets_loaded, | pf->stat_offsets_loaded, | ||||
&osd->rx_jabber, &nsd->rx_jabber); | &osd->rx_jabber, &nsd->rx_jabber); | ||||
/* EEE */ | |||||
i40e_get_phy_lpi_status(hw, nsd); | |||||
ixl_stat_update32(hw, I40E_PRTPM_TLPIC, | |||||
pf->stat_offsets_loaded, | |||||
&osd->tx_lpi_count, &nsd->tx_lpi_count); | |||||
ixl_stat_update32(hw, I40E_PRTPM_RLPIC, | |||||
pf->stat_offsets_loaded, | |||||
&osd->rx_lpi_count, &nsd->rx_lpi_count); | |||||
pf->stat_offsets_loaded = true; | pf->stat_offsets_loaded = true; | ||||
/* End hw stats */ | /* End hw stats */ | ||||
/* Update vsi stats */ | /* Update vsi stats */ | ||||
ixl_update_vsi_stats(vsi); | ixl_update_vsi_stats(vsi); | ||||
for (int i = 0; i < pf->num_vfs; i++) { | for (int i = 0; i < pf->num_vfs; i++) { | ||||
vf = &pf->vfs[i]; | vf = &pf->vfs[i]; | ||||
Show All 11 Lines | ixl_prepare_for_reset(struct ixl_pf *pf, bool is_up) | ||||
int error = 0; | int error = 0; | ||||
/* Teardown */ | /* Teardown */ | ||||
if (is_up) | if (is_up) | ||||
ixl_stop(pf); | ixl_stop(pf); | ||||
ixl_teardown_queue_msix(vsi); | ixl_teardown_queue_msix(vsi); | ||||
if (hw->hmc.hmc_obj) { | |||||
error = i40e_shutdown_lan_hmc(hw); | error = i40e_shutdown_lan_hmc(hw); | ||||
if (error) | if (error) | ||||
device_printf(dev, | device_printf(dev, | ||||
"Shutdown LAN HMC failed with code %d\n", error); | "Shutdown LAN HMC failed with code %d\n", error); | ||||
} | |||||
callout_drain(&pf->timer); | |||||
ixl_disable_intr0(hw); | ixl_disable_intr0(hw); | ||||
ixl_teardown_adminq_msix(pf); | ixl_teardown_adminq_msix(pf); | ||||
error = i40e_shutdown_adminq(hw); | error = i40e_shutdown_adminq(hw); | ||||
if (error) | if (error) | ||||
device_printf(dev, | device_printf(dev, | ||||
"Shutdown Admin queue failed with code %d\n", error); | "Shutdown Admin queue failed with code %d\n", error); | ||||
callout_drain(&pf->timer); | |||||
/* Free ring buffers, locks and filters */ | /* Free ring buffers, locks and filters */ | ||||
ixl_vsi_free_queues(vsi); | ixl_vsi_free_queues(vsi); | ||||
/* Free VSI filter list */ | |||||
ixl_free_mac_filters(vsi); | |||||
ixl_pf_qmgr_release(&pf->qmgr, &pf->qtag); | ixl_pf_qmgr_release(&pf->qmgr, &pf->qtag); | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf, bool is_up) | ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf, bool is_up) | ||||
{ | { | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
enum i40e_get_fw_lldp_status_resp lldp_status; | |||||
int error = 0; | int error = 0; | ||||
device_printf(dev, "Rebuilding driver state...\n"); | device_printf(dev, "Rebuilding driver state...\n"); | ||||
error = i40e_pf_reset(hw); | if (!(atomic_load_acq_int(&pf->state) & IXL_PF_STATE_RECOVERY_MODE)) { | ||||
if (error) { | if (ixl_fw_recovery_mode(pf)) { | ||||
device_printf(dev, "PF reset failure %s\n", | atomic_set_int(&pf->state, IXL_PF_STATE_RECOVERY_MODE); | ||||
i40e_stat_str(hw, error)); | pf->link_up = FALSE; | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | ixl_update_link_status(pf); | ||||
} | } | ||||
} | |||||
/* Setup */ | /* Setup */ | ||||
error = i40e_init_adminq(hw); | error = i40e_init_adminq(hw); | ||||
if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) { | if (error != 0 && error != I40E_ERR_FIRMWARE_API_VERSION) { | ||||
device_printf(dev, "Unable to initialize Admin Queue, error %d\n", | device_printf(dev, "Unable to initialize Admin Queue, error %d\n", | ||||
error); | error); | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | goto ixl_rebuild_hw_structs_after_reset_err; | ||||
} | } | ||||
i40e_clear_pxe_mode(hw); | i40e_clear_pxe_mode(hw); | ||||
error = ixl_get_hw_capabilities(pf); | error = ixl_get_hw_capabilities(pf); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "ixl_get_hw_capabilities failed: %d\n", error); | device_printf(dev, "ixl_get_hw_capabilities failed: %d\n", error); | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | goto ixl_rebuild_hw_structs_after_reset_err; | ||||
} | } | ||||
ixl_configure_intr0_msix(pf); | |||||
ixl_enable_intr0(hw); | |||||
/* Do not init LAN HMC and bring interface up in recovery mode */ | |||||
if ((pf->state & IXL_PF_STATE_RECOVERY_MODE) == 0) { | |||||
error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, | error = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, | ||||
hw->func_caps.num_rx_qp, 0, 0); | hw->func_caps.num_rx_qp, 0, 0); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "init_lan_hmc failed: %d\n", error); | device_printf(dev, "init_lan_hmc failed: %d\n", error); | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | goto ixl_rebuild_hw_structs_after_reset_err; | ||||
} | } | ||||
error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); | error = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "configure_lan_hmc failed: %d\n", error); | device_printf(dev, "configure_lan_hmc failed: %d\n", error); | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | goto ixl_rebuild_hw_structs_after_reset_err; | ||||
} | } | ||||
if (!pf->qmgr.qinfo) { | |||||
/* Init queue allocation manager */ | |||||
error = ixl_pf_qmgr_init(&pf->qmgr, hw->func_caps.num_rx_qp); | |||||
if (error) { | |||||
device_printf(dev, "Failed to init queue manager for PF queues, error %d\n", | |||||
error); | |||||
goto ixl_rebuild_hw_structs_after_reset_err; | |||||
} | |||||
} | |||||
/* reserve a contiguous allocation for the PF's VSI */ | /* reserve a contiguous allocation for the PF's VSI */ | ||||
error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag); | error = ixl_pf_qmgr_alloc_contiguous(&pf->qmgr, vsi->num_queues, &pf->qtag); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n", | device_printf(dev, "Failed to reserve queues for PF LAN VSI, error %d\n", | ||||
error); | error); | ||||
/* TODO: error handling */ | /* TODO: error handling */ | ||||
} | } else | ||||
device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n", | device_printf(dev, "Allocating %d queues for PF LAN VSI; %d queues active\n", | ||||
pf->qtag.num_allocated, pf->qtag.num_active); | pf->qtag.num_allocated, pf->qtag.num_active); | ||||
error = ixl_switch_config(pf); | error = ixl_switch_config(pf); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "ixl_rebuild_hw_structs_after_reset: ixl_switch_config() failed: %d\n", | device_printf(dev, "ixl_rebuild_hw_structs_after_reset: ixl_switch_config() failed: %d\n", | ||||
error); | error); | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | goto ixl_rebuild_hw_structs_after_reset_err; | ||||
} | } | ||||
} /* not in recovery mode */ | |||||
/* Remove default filters reinstalled by FW on reset */ | |||||
ixl_del_default_hw_filters(vsi); | |||||
if (ixl_vsi_setup_queues(vsi)) { | if (ixl_vsi_setup_queues(vsi)) { | ||||
device_printf(dev, "setup queues failed!\n"); | device_printf(dev, "setup queues failed!\n"); | ||||
error = ENOMEM; | error = ENOMEM; | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | goto ixl_rebuild_hw_structs_after_reset_err; | ||||
} | } | ||||
ixl_vsi_add_sysctls(vsi, "pf", true); | |||||
if (pf->msix > 1) { | if (pf->msix > 1) { | ||||
error = ixl_setup_adminq_msix(pf); | error = ixl_setup_adminq_msix(pf); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "ixl_setup_adminq_msix() error: %d\n", | device_printf(dev, "ixl_setup_adminq_msix() error: %d\n", | ||||
error); | error); | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | goto ixl_rebuild_hw_structs_after_reset_err; | ||||
} | } | ||||
ixl_configure_intr0_msix(pf); | ixl_configure_intr0_msix(pf); | ||||
ixl_enable_intr0(hw); | ixl_enable_intr0(hw); | ||||
error = ixl_setup_queue_msix(vsi); | error = ixl_setup_queue_msix(vsi); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "ixl_setup_queue_msix() error: %d\n", | device_printf(dev, "ixl_setup_queue_msix() error: %d\n", | ||||
error); | error); | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | goto ixl_rebuild_hw_structs_after_reset_err; | ||||
} | } | ||||
error = ixl_setup_queue_tqs(vsi); | |||||
if (error) { | |||||
device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", | |||||
error); | |||||
goto ixl_rebuild_hw_structs_after_reset_err; | |||||
} | |||||
} else { | } else { | ||||
error = ixl_setup_legacy(pf); | error = ixl_setup_legacy(pf); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "ixl_setup_legacy() error: %d\n", | device_printf(dev, "ixl_setup_legacy() error: %d\n", | ||||
error); | error); | ||||
goto ixl_rebuild_hw_structs_after_reset_err; | goto ixl_rebuild_hw_structs_after_reset_err; | ||||
} | } | ||||
} | } | ||||
/* Do not bring interface up in recovery mode */ | |||||
if ((pf->state & IXL_PF_STATE_RECOVERY_MODE) != 0) | |||||
return (error); | |||||
/* Determine link state */ | /* Determine link state */ | ||||
if (ixl_attach_get_link_status(pf)) { | if (ixl_attach_get_link_status(pf)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
/* TODO: error handling */ | /* TODO: error handling */ | ||||
} | } | ||||
i40e_aq_set_dcb_parameters(hw, TRUE, NULL); | i40e_aq_set_dcb_parameters(hw, TRUE, NULL); | ||||
ixl_get_fw_lldp_status(pf); | |||||
/* Query device FW LLDP status */ | |||||
if (i40e_get_fw_lldp_status(hw, &lldp_status) == I40E_SUCCESS) { | |||||
if (lldp_status == I40E_GET_FW_LLDP_STATUS_DISABLED) { | |||||
atomic_set_int(&pf->state, | |||||
IXL_PF_STATE_FW_LLDP_DISABLED); | |||||
} else { | |||||
atomic_clear_int(&pf->state, | |||||
IXL_PF_STATE_FW_LLDP_DISABLED); | |||||
} | |||||
} | |||||
if (is_up) | if (is_up) | ||||
ixl_init(pf); | ixl_init(pf); | ||||
device_printf(dev, "Rebuilding driver state done.\n"); | device_printf(dev, "Rebuilding driver state done.\n"); | ||||
IXL_PF_LOCK(pf); | |||||
callout_reset(&pf->timer, hz, ixl_local_timer, pf); | |||||
IXL_PF_UNLOCK(pf); | |||||
return (0); | return (0); | ||||
ixl_rebuild_hw_structs_after_reset_err: | ixl_rebuild_hw_structs_after_reset_err: | ||||
device_printf(dev, "Reload the driver to recover\n"); | device_printf(dev, "Reload the driver to recover\n"); | ||||
return (error); | return (error); | ||||
} | } | ||||
void | void | ||||
ixl_handle_empr_reset(struct ixl_pf *pf) | ixl_handle_empr_reset(struct ixl_pf *pf) | ||||
{ | { | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
bool is_up = !!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING); | bool is_up = !!(vsi->ifp->if_drv_flags & IFF_DRV_RUNNING); | ||||
int count = 0; | int error = 0; | ||||
u32 reg; | |||||
ixl_prepare_for_reset(pf, is_up); | ixl_prepare_for_reset(pf, is_up); | ||||
/* | |||||
/* Typically finishes within 3-4 seconds */ | * i40e_pf_reset checks the type of reset and acts | ||||
while (count++ < 100) { | * accordingly. If EMP or Core reset was performed | ||||
reg = rd32(hw, I40E_GLGEN_RSTAT) | * doing PF reset is not necessary and it sometimes | ||||
& I40E_GLGEN_RSTAT_DEVSTATE_MASK; | * fails. | ||||
if (reg) | */ | ||||
i40e_msec_delay(100); | error = i40e_pf_reset(hw); | ||||
else | if (error) { | ||||
break; | device_printf(pf->dev, "PF reset failure %s\n", | ||||
i40e_stat_str(hw, error)); | |||||
} | } | ||||
ixl_dbg(pf, IXL_DBG_INFO, | |||||
"EMPR reset wait count: %d\n", count); | |||||
ixl_rebuild_hw_structs_after_reset(pf, is_up); | ixl_rebuild_hw_structs_after_reset(pf, is_up); | ||||
atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); | atomic_clear_int(&pf->state, IXL_PF_STATE_EMPR_RESETTING); | ||||
} | } | ||||
/* | /* | ||||
** Tasklet handler for MSIX Adminq interrupts | ** Tasklet handler for MSIX Adminq interrupts | ||||
** - do outside interrupt since it might sleep | ** - do outside interrupt since it might sleep | ||||
*/ | */ | ||||
void | void | ||||
ixl_do_adminq(void *context, int pending) | ixl_do_adminq(void *context, int pending) | ||||
{ | { | ||||
struct ixl_pf *pf = context; | struct ixl_pf *pf = context; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct i40e_arq_event_info event; | struct i40e_arq_event_info event; | ||||
i40e_status ret; | i40e_status ret; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
u32 loop = 0; | u32 loop = 0; | ||||
u16 opcode, result; | u16 opcode, arq_pending; | ||||
if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { | if (pf->state & IXL_PF_STATE_EMPR_RESETTING) { | ||||
/* Flag cleared at end of this function */ | /* Flag cleared at end of this function */ | ||||
ixl_handle_empr_reset(pf); | ixl_handle_empr_reset(pf); | ||||
return; | return; | ||||
} | } | ||||
/* Admin Queue handling */ | /* Admin Queue handling */ | ||||
event.buf_len = IXL_AQ_BUF_SZ; | event.buf_len = IXL_AQ_BUF_SZ; | ||||
event.msg_buf = malloc(event.buf_len, | event.msg_buf = malloc(event.buf_len, | ||||
M_DEVBUF, M_NOWAIT | M_ZERO); | M_DEVBUF, M_NOWAIT | M_ZERO); | ||||
if (!event.msg_buf) { | if (!event.msg_buf) { | ||||
device_printf(dev, "%s: Unable to allocate memory for Admin" | device_printf(dev, "%s: Unable to allocate memory for Admin" | ||||
" Queue event!\n", __func__); | " Queue event!\n", __func__); | ||||
return; | return; | ||||
} | } | ||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
/* clean and process any events */ | /* clean and process any events */ | ||||
do { | do { | ||||
ret = i40e_clean_arq_element(hw, &event, &result); | ret = i40e_clean_arq_element(hw, &event, &arq_pending); | ||||
if (ret) | if (ret) | ||||
break; | break; | ||||
opcode = LE16_TO_CPU(event.desc.opcode); | opcode = LE16_TO_CPU(event.desc.opcode); | ||||
ixl_dbg(pf, IXL_DBG_AQ, | ixl_dbg(pf, IXL_DBG_AQ, | ||||
"Admin Queue event: %#06x\n", opcode); | "Admin Queue event: %#06x\n", opcode); | ||||
switch (opcode) { | switch (opcode) { | ||||
case i40e_aqc_opc_get_link_status: | case i40e_aqc_opc_get_link_status: | ||||
ixl_link_event(pf, &event); | ixl_link_event(pf, &event); | ||||
break; | break; | ||||
case i40e_aqc_opc_send_msg_to_pf: | case i40e_aqc_opc_send_msg_to_pf: | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
ixl_handle_vf_msg(pf, &event); | ixl_handle_vf_msg(pf, &event); | ||||
#endif | #endif | ||||
break; | break; | ||||
case i40e_aqc_opc_event_lan_overflow: | case i40e_aqc_opc_event_lan_overflow: | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} while (result && (loop++ < IXL_ADM_LIMIT)); | } while (arq_pending && (loop++ < IXL_ADM_LIMIT)); | ||||
free(event.msg_buf, M_DEVBUF); | free(event.msg_buf, M_DEVBUF); | ||||
/* | /* If there are still messages to process, reschedule. */ | ||||
* If there are still messages to process, reschedule ourselves. | if (arq_pending > 0) | ||||
* Otherwise, re-enable our interrupt. | |||||
*/ | |||||
if (result > 0) | |||||
taskqueue_enqueue(pf->tq, &pf->adminq); | taskqueue_enqueue(pf->tq, &pf->adminq); | ||||
else | else | ||||
ixl_enable_intr0(hw); | ixl_enable_intr0(hw); | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
} | } | ||||
/** | /** | ||||
* Update VSI-specific ethernet statistics counters. | * Update VSI-specific ethernet statistics counters. | ||||
**/ | **/ | ||||
void | void | ||||
ixl_update_eth_stats(struct ixl_vsi *vsi) | ixl_update_eth_stats(struct ixl_vsi *vsi) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)vsi->back; | struct ixl_pf *pf = (struct ixl_pf *)vsi->back; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct i40e_eth_stats *es; | struct i40e_eth_stats *es; | ||||
struct i40e_eth_stats *oes; | struct i40e_eth_stats *oes; | ||||
struct i40e_hw_port_stats *nsd; | |||||
u16 stat_idx = vsi->info.stat_counter_idx; | u16 stat_idx = vsi->info.stat_counter_idx; | ||||
es = &vsi->eth_stats; | es = &vsi->eth_stats; | ||||
oes = &vsi->eth_stats_offsets; | oes = &vsi->eth_stats_offsets; | ||||
nsd = &pf->stats; | |||||
/* Gather up the stats that the hw collects */ | /* Gather up the stats that the hw collects */ | ||||
ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), | ixl_stat_update32(hw, I40E_GLV_TEPC(stat_idx), | ||||
vsi->stat_offsets_loaded, | vsi->stat_offsets_loaded, | ||||
&oes->tx_errors, &es->tx_errors); | &oes->tx_errors, &es->tx_errors); | ||||
ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), | ixl_stat_update32(hw, I40E_GLV_RDPC(stat_idx), | ||||
vsi->stat_offsets_loaded, | vsi->stat_offsets_loaded, | ||||
&oes->rx_discards, &es->rx_discards); | &oes->rx_discards, &es->rx_discards); | ||||
▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | struct sysctl_oid_list *ctx_list = | ||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); | SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); | ||||
struct sysctl_oid *debug_node; | struct sysctl_oid *debug_node; | ||||
struct sysctl_oid_list *debug_list; | struct sysctl_oid_list *debug_list; | ||||
struct sysctl_oid *fec_node; | struct sysctl_oid *fec_node; | ||||
struct sysctl_oid_list *fec_list; | struct sysctl_oid_list *fec_list; | ||||
struct sysctl_oid *eee_node; | |||||
struct sysctl_oid_list *eee_list; | |||||
/* Set up sysctls */ | /* Set up sysctls */ | ||||
SYSCTL_ADD_PROC(ctx, ctx_list, | SYSCTL_ADD_PROC(ctx, ctx_list, | ||||
OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, | OID_AUTO, "fc", CTLTYPE_INT | CTLFLAG_RW, | ||||
pf, 0, ixl_sysctl_set_flowcntl, "I", IXL_SYSCTL_HELP_FC); | pf, 0, ixl_sysctl_set_flowcntl, "I", IXL_SYSCTL_HELP_FC); | ||||
SYSCTL_ADD_PROC(ctx, ctx_list, | SYSCTL_ADD_PROC(ctx, ctx_list, | ||||
OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, | OID_AUTO, "advertise_speed", CTLTYPE_INT | CTLFLAG_RW, | ||||
pf, 0, ixl_sysctl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE); | pf, 0, ixl_sysctl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | SYSCTL_ADD_PROC(ctx, fec_list, | ||||
OID_AUTO, "auto_fec_enabled", CTLTYPE_INT | CTLFLAG_RW, | OID_AUTO, "auto_fec_enabled", CTLTYPE_INT | CTLFLAG_RW, | ||||
pf, 0, ixl_sysctl_fec_auto_enable, "I", "Let FW decide FEC ability/request modes"); | pf, 0, ixl_sysctl_fec_auto_enable, "I", "Let FW decide FEC ability/request modes"); | ||||
} | } | ||||
SYSCTL_ADD_PROC(ctx, ctx_list, | SYSCTL_ADD_PROC(ctx, ctx_list, | ||||
OID_AUTO, "fw_lldp", CTLTYPE_INT | CTLFLAG_RW, | OID_AUTO, "fw_lldp", CTLTYPE_INT | CTLFLAG_RW, | ||||
pf, 0, ixl_sysctl_fw_lldp, "I", IXL_SYSCTL_HELP_FW_LLDP); | pf, 0, ixl_sysctl_fw_lldp, "I", IXL_SYSCTL_HELP_FW_LLDP); | ||||
eee_node = SYSCTL_ADD_NODE(ctx, ctx_list, | |||||
OID_AUTO, "eee", CTLFLAG_RD, NULL, | |||||
"Energy Efficient Ethernet (EEE) Sysctls"); | |||||
eee_list = SYSCTL_CHILDREN(eee_node); | |||||
SYSCTL_ADD_PROC(ctx, eee_list, | |||||
OID_AUTO, "enable", CTLTYPE_INT | CTLFLAG_RW, | |||||
pf, 0, ixl_sysctl_eee_enable, "I", | |||||
"Enable Energy Efficient Ethernet (EEE)"); | |||||
SYSCTL_ADD_UINT(ctx, eee_list, OID_AUTO, "tx_lpi_status", | |||||
CTLFLAG_RD, &pf->stats.tx_lpi_status, 0, | |||||
"TX LPI status"); | |||||
SYSCTL_ADD_UINT(ctx, eee_list, OID_AUTO, "rx_lpi_status", | |||||
CTLFLAG_RD, &pf->stats.rx_lpi_status, 0, | |||||
"RX LPI status"); | |||||
SYSCTL_ADD_UQUAD(ctx, eee_list, OID_AUTO, "tx_lpi_count", | |||||
CTLFLAG_RD, &pf->stats.tx_lpi_count, | |||||
"TX LPI count"); | |||||
SYSCTL_ADD_UQUAD(ctx, eee_list, OID_AUTO, "rx_lpi_count", | |||||
CTLFLAG_RD, &pf->stats.rx_lpi_count, | |||||
"RX LPI count"); | |||||
/* Add sysctls meant to print debug information, but don't list them | /* Add sysctls meant to print debug information, but don't list them | ||||
* in "sysctl -a" output. */ | * in "sysctl -a" output. */ | ||||
debug_node = SYSCTL_ADD_NODE(ctx, ctx_list, | debug_node = SYSCTL_ADD_NODE(ctx, ctx_list, | ||||
OID_AUTO, "debug", CTLFLAG_RD | CTLFLAG_SKIP, NULL, "Debug Sysctls"); | OID_AUTO, "debug", CTLFLAG_RD | CTLFLAG_SKIP, NULL, "Debug Sysctls"); | ||||
debug_list = SYSCTL_CHILDREN(debug_node); | debug_list = SYSCTL_CHILDREN(debug_node); | ||||
SYSCTL_ADD_UINT(ctx, debug_list, | SYSCTL_ADD_UINT(ctx, debug_list, | ||||
OID_AUTO, "shared_debug_mask", CTLFLAG_RW, | OID_AUTO, "shared_debug_mask", CTLFLAG_RW, | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | ixl_add_device_sysctls(struct ixl_pf *pf) | ||||
if (pf->has_i2c) { | if (pf->has_i2c) { | ||||
SYSCTL_ADD_PROC(ctx, debug_list, | SYSCTL_ADD_PROC(ctx, debug_list, | ||||
OID_AUTO, "read_i2c_byte", CTLTYPE_INT | CTLFLAG_RW, | OID_AUTO, "read_i2c_byte", CTLTYPE_INT | CTLFLAG_RW, | ||||
pf, 0, ixl_sysctl_read_i2c_byte, "I", "Read byte from I2C bus"); | pf, 0, ixl_sysctl_read_i2c_byte, "I", "Read byte from I2C bus"); | ||||
SYSCTL_ADD_PROC(ctx, debug_list, | SYSCTL_ADD_PROC(ctx, debug_list, | ||||
OID_AUTO, "write_i2c_byte", CTLTYPE_INT | CTLFLAG_RW, | OID_AUTO, "write_i2c_byte", CTLTYPE_INT | CTLFLAG_RW, | ||||
pf, 0, ixl_sysctl_write_i2c_byte, "I", "Write byte to I2C bus"); | pf, 0, ixl_sysctl_write_i2c_byte, "I", "Write byte to I2C bus"); | ||||
SYSCTL_ADD_PROC(ctx, debug_list, | |||||
OID_AUTO, "read_i2c_diag_data", CTLTYPE_STRING | CTLFLAG_RD, | |||||
pf, 0, ixl_sysctl_read_i2c_diag_data, "A", "Dump selected diagnostic data from FW"); | |||||
} | } | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
SYSCTL_ADD_UINT(ctx, debug_list, | SYSCTL_ADD_UINT(ctx, debug_list, | ||||
OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl, | OID_AUTO, "vc_debug_level", CTLFLAG_RW, &pf->vc_debug_lvl, | ||||
0, "PF/VF Virtual Channel debug level"); | 0, "PF/VF Virtual Channel debug level"); | ||||
#endif | #endif | ||||
} | } | ||||
Show All 32 Lines | ixl_sysctl_set_flowcntl(SYSCTL_HANDLER_ARGS) | ||||
enum i40e_status_code aq_error = 0; | enum i40e_status_code aq_error = 0; | ||||
u8 fc_aq_err = 0; | u8 fc_aq_err = 0; | ||||
/* Get request */ | /* Get request */ | ||||
requested_fc = pf->fc; | requested_fc = pf->fc; | ||||
error = sysctl_handle_int(oidp, &requested_fc, 0, req); | error = sysctl_handle_int(oidp, &requested_fc, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
if ((pf->state & IXL_PF_STATE_RECOVERY_MODE) != 0) { | |||||
device_printf(dev, "Interface is currently in FW recovery mode. " | |||||
"Setting flow control not supported\n"); | |||||
return (EINVAL); | |||||
} | |||||
if (requested_fc < 0 || requested_fc > 3) { | if (requested_fc < 0 || requested_fc > 3) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Invalid fc mode; valid modes are 0 through 3\n"); | "Invalid fc mode; valid modes are 0 through 3\n"); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* Set fc ability for port */ | /* Set fc ability for port */ | ||||
hw->fc.requested_mode = requested_fc; | hw->fc.requested_mode = requested_fc; | ||||
Show All 9 Lines | ixl_sysctl_set_flowcntl(SYSCTL_HANDLER_ARGS) | ||||
/* Get new link state */ | /* Get new link state */ | ||||
i40e_msec_delay(250); | i40e_msec_delay(250); | ||||
hw->phy.get_link_info = TRUE; | hw->phy.get_link_info = TRUE; | ||||
i40e_get_link_status(hw, &pf->link_up); | i40e_get_link_status(hw, &pf->link_up); | ||||
return (0); | return (0); | ||||
} | } | ||||
char * | |||||
ixl_aq_speed_to_str(enum i40e_aq_link_speed link_speed) | |||||
{ | |||||
int index; | |||||
char *speeds[] = { | static const char * | ||||
ixl_link_speed_string(u8 link_speed) | |||||
{ | |||||
const char * link_speed_str[] = { | |||||
"Unknown", | "Unknown", | ||||
"100 Mbps", | "100 Mbps", | ||||
"1 Gbps", | "1 Gbps", | ||||
"10 Gbps", | "10 Gbps", | ||||
"40 Gbps", | "40 Gbps", | ||||
"20 Gbps", | "20 Gbps", | ||||
"25 Gbps", | "25 Gbps", | ||||
"2.5 Gbps", | |||||
"5 Gbps" | |||||
}; | }; | ||||
int index; | |||||
switch (link_speed) { | switch (link_speed) { | ||||
case I40E_LINK_SPEED_100MB: | case I40E_LINK_SPEED_100MB: | ||||
index = 1; | index = 1; | ||||
break; | break; | ||||
case I40E_LINK_SPEED_1GB: | case I40E_LINK_SPEED_1GB: | ||||
index = 2; | index = 2; | ||||
break; | break; | ||||
case I40E_LINK_SPEED_10GB: | case I40E_LINK_SPEED_10GB: | ||||
index = 3; | index = 3; | ||||
break; | break; | ||||
case I40E_LINK_SPEED_40GB: | case I40E_LINK_SPEED_40GB: | ||||
index = 4; | index = 4; | ||||
break; | break; | ||||
case I40E_LINK_SPEED_20GB: | case I40E_LINK_SPEED_20GB: | ||||
index = 5; | index = 5; | ||||
break; | break; | ||||
case I40E_LINK_SPEED_25GB: | case I40E_LINK_SPEED_25GB: | ||||
index = 6; | index = 6; | ||||
break; | break; | ||||
case I40E_LINK_SPEED_2_5GB: | |||||
index = 7; | |||||
break; | |||||
case I40E_LINK_SPEED_5GB: | |||||
index = 8; | |||||
break; | |||||
case I40E_LINK_SPEED_UNKNOWN: | case I40E_LINK_SPEED_UNKNOWN: | ||||
default: | default: | ||||
index = 0; | index = 0; | ||||
break; | break; | ||||
} | } | ||||
return speeds[index]; | return (link_speed_str[index]); | ||||
} | } | ||||
int | int | ||||
ixl_sysctl_current_speed(SYSCTL_HANDLER_ARGS) | ixl_sysctl_current_speed(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | struct ixl_pf *pf = (struct ixl_pf *)arg1; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
int error = 0; | int error = 0; | ||||
ixl_update_link_status(pf); | ixl_update_link_status(pf); | ||||
error = sysctl_handle_string(oidp, | error = sysctl_handle_string(oidp, | ||||
ixl_aq_speed_to_str(hw->phy.link_info.link_speed), | __DECONST(void *, | ||||
ixl_link_speed_string(hw->phy.link_info.link_speed)), | |||||
8, req); | 8, req); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Converts 8-bit speeds value to and from sysctl flags and | * Converts 8-bit speeds value to and from sysctl flags and | ||||
* Admin Queue flags. | * Admin Queue flags. | ||||
*/ | */ | ||||
static u8 | static u8 | ||||
ixl_convert_sysctl_aq_link_speed(u8 speeds, bool to_aq) | ixl_convert_sysctl_aq_link_speed(u8 speeds, bool to_aq) | ||||
{ | { | ||||
static u16 speedmap[6] = { | #define SPEED_MAP_SIZE 8 | ||||
static u16 speedmap[SPEED_MAP_SIZE] = { | |||||
(I40E_LINK_SPEED_100MB | (0x1 << 8)), | (I40E_LINK_SPEED_100MB | (0x1 << 8)), | ||||
(I40E_LINK_SPEED_1GB | (0x2 << 8)), | (I40E_LINK_SPEED_1GB | (0x2 << 8)), | ||||
(I40E_LINK_SPEED_10GB | (0x4 << 8)), | (I40E_LINK_SPEED_10GB | (0x4 << 8)), | ||||
(I40E_LINK_SPEED_20GB | (0x8 << 8)), | (I40E_LINK_SPEED_20GB | (0x8 << 8)), | ||||
(I40E_LINK_SPEED_25GB | (0x10 << 8)), | (I40E_LINK_SPEED_25GB | (0x10 << 8)), | ||||
(I40E_LINK_SPEED_40GB | (0x20 << 8)) | (I40E_LINK_SPEED_40GB | (0x20 << 8)), | ||||
(I40E_LINK_SPEED_2_5GB | (0x40 << 8)), | |||||
(I40E_LINK_SPEED_5GB | (0x80 << 8)), | |||||
}; | }; | ||||
u8 retval = 0; | u8 retval = 0; | ||||
for (int i = 0; i < 6; i++) { | for (int i = 0; i < SPEED_MAP_SIZE; i++) { | ||||
if (to_aq) | if (to_aq) | ||||
retval |= (speeds & (speedmap[i] >> 8)) ? (speedmap[i] & 0xff) : 0; | retval |= (speeds & (speedmap[i] >> 8)) ? (speedmap[i] & 0xff) : 0; | ||||
else | else | ||||
retval |= (speeds & speedmap[i]) ? (speedmap[i] >> 8) : 0; | retval |= (speeds & speedmap[i]) ? (speedmap[i] >> 8) : 0; | ||||
} | } | ||||
return (retval); | return (retval); | ||||
} | } | ||||
Show All 26 Lines | else | ||||
config.link_speed = ixl_convert_sysctl_aq_link_speed(speeds, true); | config.link_speed = ixl_convert_sysctl_aq_link_speed(speeds, true); | ||||
config.phy_type = abilities.phy_type; | config.phy_type = abilities.phy_type; | ||||
config.phy_type_ext = abilities.phy_type_ext; | config.phy_type_ext = abilities.phy_type_ext; | ||||
config.abilities = abilities.abilities | config.abilities = abilities.abilities | ||||
| I40E_AQ_PHY_ENABLE_ATOMIC_LINK; | | I40E_AQ_PHY_ENABLE_ATOMIC_LINK; | ||||
config.eee_capability = abilities.eee_capability; | config.eee_capability = abilities.eee_capability; | ||||
config.eeer = abilities.eeer_val; | config.eeer = abilities.eeer_val; | ||||
config.low_power_ctrl = abilities.d3_lpan; | config.low_power_ctrl = abilities.d3_lpan; | ||||
config.fec_config = (abilities.fec_cfg_curr_mod_ext_info & 0x1e); | config.fec_config = abilities.fec_cfg_curr_mod_ext_info | ||||
& I40E_AQ_PHY_FEC_CONFIG_MASK; | |||||
/* Do aq command & restart link */ | /* Do aq command & restart link */ | ||||
aq_error = i40e_aq_set_phy_config(hw, &config, NULL); | aq_error = i40e_aq_set_phy_config(hw, &config, NULL); | ||||
if (aq_error) { | if (aq_error) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: Error setting new phy config %d," | "%s: Error setting new phy config %d," | ||||
" aq error: %d\n", __func__, aq_error, | " aq error: %d\n", __func__, aq_error, | ||||
hw->aq.asq_last_status); | hw->aq.asq_last_status); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
** Supported link speedsL | ** Supported link speeds | ||||
** Flags: | ** Flags: | ||||
** 0x1 - 100 Mb | ** 0x1 - 100 Mb | ||||
** 0x2 - 1G | ** 0x2 - 1G | ||||
** 0x4 - 10G | ** 0x4 - 10G | ||||
** 0x8 - 20G | ** 0x8 - 20G | ||||
** 0x10 - 25G | ** 0x10 - 25G | ||||
** 0x20 - 40G | ** 0x20 - 40G | ||||
** 0x40 - 2.5G | |||||
** 0x80 - 5G | |||||
*/ | */ | ||||
static int | static int | ||||
ixl_sysctl_supported_speeds(SYSCTL_HANDLER_ARGS) | ixl_sysctl_supported_speeds(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | struct ixl_pf *pf = (struct ixl_pf *)arg1; | ||||
int supported = ixl_convert_sysctl_aq_link_speed(pf->supported_speeds, false); | int supported = ixl_convert_sysctl_aq_link_speed(pf->supported_speeds, false); | ||||
return sysctl_handle_int(oidp, NULL, supported, req); | return sysctl_handle_int(oidp, NULL, supported, req); | ||||
} | } | ||||
/* | /* | ||||
** Control link advertise speed: | ** Control link advertise speed: | ||||
** Flags: | ** Flags: | ||||
** 0x1 - advertise 100 Mb | ** 0x1 - advertise 100 Mb | ||||
** 0x2 - advertise 1G | ** 0x2 - advertise 1G | ||||
** 0x4 - advertise 10G | ** 0x4 - advertise 10G | ||||
** 0x8 - advertise 20G | ** 0x8 - advertise 20G | ||||
** 0x10 - advertise 25G | ** 0x10 - advertise 25G | ||||
** 0x20 - advertise 40G | ** 0x20 - advertise 40G | ||||
** 0x40 - advertise 2.5G | |||||
** 0x80 - advertise 5G | |||||
** | ** | ||||
** Set to 0 to disable link | ** Set to 0 to disable link | ||||
*/ | */ | ||||
int | int | ||||
ixl_sysctl_set_advertise(SYSCTL_HANDLER_ARGS) | ixl_sysctl_set_advertise(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | struct ixl_pf *pf = (struct ixl_pf *)arg1; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
u8 converted_speeds; | u8 converted_speeds; | ||||
int requested_ls = 0; | int requested_ls = 0; | ||||
int error = 0; | int error = 0; | ||||
/* Read in new mode */ | /* Read in new mode */ | ||||
requested_ls = pf->advertised_speed; | requested_ls = pf->advertised_speed; | ||||
error = sysctl_handle_int(oidp, &requested_ls, 0, req); | error = sysctl_handle_int(oidp, &requested_ls, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
if ((pf->state & IXL_PF_STATE_RECOVERY_MODE) != 0) { | |||||
device_printf(dev, "Interface is currently in FW recovery mode. " | |||||
"Setting advertise speed not supported\n"); | |||||
return (EINVAL); | |||||
} | |||||
/* Error out if bits outside of possible flag range are set */ | /* Error out if bits outside of possible flag range are set */ | ||||
if ((requested_ls & ~((u8)0x3F)) != 0) { | if ((requested_ls & ~((u8)0xFF)) != 0) { | ||||
device_printf(dev, "Input advertised speed out of range; " | device_printf(dev, "Input advertised speed out of range; " | ||||
"valid flags are: 0x%02x\n", | "valid flags are: 0x%02x\n", | ||||
ixl_convert_sysctl_aq_link_speed(pf->supported_speeds, false)); | ixl_convert_sysctl_aq_link_speed(pf->supported_speeds, false)); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* Check if adapter supports input value */ | /* Check if adapter supports input value */ | ||||
converted_speeds = ixl_convert_sysctl_aq_link_speed((u8)requested_ls, true); | converted_speeds = ixl_convert_sysctl_aq_link_speed((u8)requested_ls, true); | ||||
Show All 22 Lines | ixl_max_aq_speed_to_value(u8 link_speeds) | ||||
if (link_speeds & I40E_LINK_SPEED_40GB) | if (link_speeds & I40E_LINK_SPEED_40GB) | ||||
return IF_Gbps(40); | return IF_Gbps(40); | ||||
if (link_speeds & I40E_LINK_SPEED_25GB) | if (link_speeds & I40E_LINK_SPEED_25GB) | ||||
return IF_Gbps(25); | return IF_Gbps(25); | ||||
if (link_speeds & I40E_LINK_SPEED_20GB) | if (link_speeds & I40E_LINK_SPEED_20GB) | ||||
return IF_Gbps(20); | return IF_Gbps(20); | ||||
if (link_speeds & I40E_LINK_SPEED_10GB) | if (link_speeds & I40E_LINK_SPEED_10GB) | ||||
return IF_Gbps(10); | return IF_Gbps(10); | ||||
if (link_speeds & I40E_LINK_SPEED_5GB) | |||||
return IF_Gbps(5); | |||||
if (link_speeds & I40E_LINK_SPEED_2_5GB) | |||||
return IF_Mbps(2500); | |||||
if (link_speeds & I40E_LINK_SPEED_1GB) | if (link_speeds & I40E_LINK_SPEED_1GB) | ||||
return IF_Gbps(1); | return IF_Gbps(1); | ||||
if (link_speeds & I40E_LINK_SPEED_100MB) | if (link_speeds & I40E_LINK_SPEED_100MB) | ||||
return IF_Mbps(100); | return IF_Mbps(100); | ||||
else | else | ||||
/* Minimum supported link speed */ | /* Minimum supported link speed */ | ||||
return IF_Mbps(100); | return IF_Mbps(100); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | ixl_handle_nvmupd_cmd(struct ixl_pf *pf, struct ifdrv *ifd) | ||||
* to run this ioctl again. So use -EACCES for -EPERM instead. | * to run this ioctl again. So use -EACCES for -EPERM instead. | ||||
*/ | */ | ||||
if (perrno == -EPERM) | if (perrno == -EPERM) | ||||
return (-EACCES); | return (-EACCES); | ||||
else | else | ||||
return (perrno); | return (perrno); | ||||
} | } | ||||
int | |||||
ixl_handle_i2c_eeprom_read_cmd(struct ixl_pf *pf, struct ifreq *ifr) | |||||
{ | |||||
struct ifi2creq i2c; | |||||
int error = 0; | |||||
int i; | |||||
if (pf->read_i2c_byte == NULL) | |||||
return (EINVAL); | |||||
#ifdef ifr_data | |||||
error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); | |||||
#else | |||||
error = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c)); | |||||
#endif | |||||
if (error != 0) | |||||
return (error); | |||||
if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { | |||||
error = EINVAL; | |||||
return (error); | |||||
} | |||||
if (i2c.len > sizeof(i2c.data)) { | |||||
error = EINVAL; | |||||
return (error); | |||||
} | |||||
for (i = 0; i < i2c.len; ++i) { | |||||
if (pf->read_i2c_byte(pf, i2c.offset + i, | |||||
i2c.dev_addr, &i2c.data[i])) | |||||
return (EIO); | |||||
} | |||||
#ifdef ifr_data | |||||
error = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); | |||||
#else | |||||
error = copyout(&i2c, ifr_data_get_ptr(ifr), sizeof(i2c)); | |||||
#endif | |||||
return (error); | |||||
} | |||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* Media Ioctl callback | * Media Ioctl callback | ||||
* | * | ||||
* This routine is called whenever the user queries the status of | * This routine is called whenever the user queries the status of | ||||
* the interface using ifconfig. | * the interface using ifconfig. | ||||
* | * | ||||
* When adding new media types here, make sure to add them to | * When adding new media types here, make sure to add them to | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | case I40E_PHY_TYPE_1000BASE_SX: | ||||
ifmr->ifm_active |= IFM_1000_SX; | ifmr->ifm_active |= IFM_1000_SX; | ||||
break; | break; | ||||
case I40E_PHY_TYPE_1000BASE_LX: | case I40E_PHY_TYPE_1000BASE_LX: | ||||
ifmr->ifm_active |= IFM_1000_LX; | ifmr->ifm_active |= IFM_1000_LX; | ||||
break; | break; | ||||
case I40E_PHY_TYPE_1000BASE_T_OPTICAL: | case I40E_PHY_TYPE_1000BASE_T_OPTICAL: | ||||
ifmr->ifm_active |= IFM_1000_T; | ifmr->ifm_active |= IFM_1000_T; | ||||
break; | break; | ||||
/* 2.5 G */ | |||||
case I40E_PHY_TYPE_2_5GBASE_T: | |||||
ifmr->ifm_active |= IFM_2500_T; | |||||
break; | |||||
/* 5 G */ | |||||
case I40E_PHY_TYPE_5GBASE_T: | |||||
ifmr->ifm_active |= IFM_5000_T; | |||||
break; | |||||
/* 10 G */ | /* 10 G */ | ||||
case I40E_PHY_TYPE_10GBASE_SFPP_CU: | case I40E_PHY_TYPE_10GBASE_SFPP_CU: | ||||
ifmr->ifm_active |= IFM_10G_TWINAX; | ifmr->ifm_active |= IFM_10G_TWINAX; | ||||
break; | break; | ||||
case I40E_PHY_TYPE_10GBASE_SR: | case I40E_PHY_TYPE_10GBASE_SR: | ||||
ifmr->ifm_active |= IFM_10G_SR; | ifmr->ifm_active |= IFM_10G_SR; | ||||
break; | break; | ||||
case I40E_PHY_TYPE_10GBASE_LR: | case I40E_PHY_TYPE_10GBASE_LR: | ||||
▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | ixl_ioctl(struct ifnet * ifp, u_long command, caddr_t data) | ||||
struct ifreq *ifr = (struct ifreq *)data; | struct ifreq *ifr = (struct ifreq *)data; | ||||
struct ifdrv *ifd = (struct ifdrv *)data; | struct ifdrv *ifd = (struct ifdrv *)data; | ||||
#if defined(INET) || defined(INET6) | #if defined(INET) || defined(INET6) | ||||
struct ifaddr *ifa = (struct ifaddr *)data; | struct ifaddr *ifa = (struct ifaddr *)data; | ||||
bool avoid_reset = FALSE; | bool avoid_reset = FALSE; | ||||
#endif | #endif | ||||
int error = 0; | int error = 0; | ||||
if ((atomic_load_acq_int(&pf->state) & IXL_PF_STATE_RECOVERY_MODE) != 0) { | |||||
/* We are in recovery mode supporting only NVM update */ | |||||
switch (command) { | switch (command) { | ||||
case SIOCSDRVSPEC: | |||||
case SIOCGDRVSPEC: | |||||
IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific " | |||||
"Info)\n"); | |||||
/* NVM update command */ | |||||
if (ifd->ifd_cmd == I40E_NVM_ACCESS) | |||||
error = ixl_handle_nvmupd_cmd(pf, ifd); | |||||
else | |||||
error = EINVAL; | |||||
break; | |||||
default: | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
return (error); | |||||
} | |||||
switch (command) { | |||||
case SIOCSIFADDR: | case SIOCSIFADDR: | ||||
IOCTL_DEBUGOUT("ioctl: SIOCSIFADDR (Set Interface Address)"); | IOCTL_DEBUGOUT("ioctl: SIOCSIFADDR (Set Interface Address)"); | ||||
#ifdef INET | #ifdef INET | ||||
if (ifa->ifa_addr->sa_family == AF_INET) | if (ifa->ifa_addr->sa_family == AF_INET) | ||||
avoid_reset = TRUE; | avoid_reset = TRUE; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
if (ifa->ifa_addr->sa_family == AF_INET6) | if (ifa->ifa_addr->sa_family == AF_INET6) | ||||
Show All 35 Lines | case SIOCSIFFLAGS: | ||||
IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); | IOCTL_DEBUGOUT("ioctl: SIOCSIFFLAGS (Set Interface Flags)"); | ||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
if (ifp->if_flags & IFF_UP) { | if (ifp->if_flags & IFF_UP) { | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { | if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { | ||||
if ((ifp->if_flags ^ pf->if_flags) & | if ((ifp->if_flags ^ pf->if_flags) & | ||||
(IFF_PROMISC | IFF_ALLMULTI)) { | (IFF_PROMISC | IFF_ALLMULTI)) { | ||||
ixl_set_promisc(vsi); | ixl_set_promisc(vsi); | ||||
} | } | ||||
} else { | } else | ||||
IXL_PF_UNLOCK(pf); | ixl_init_locked(pf); | ||||
ixl_init(pf); | } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) | ||||
IXL_PF_LOCK(pf); | |||||
} | |||||
} else { | |||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | |||||
ixl_stop_locked(pf); | ixl_stop_locked(pf); | ||||
} | |||||
} | |||||
pf->if_flags = ifp->if_flags; | pf->if_flags = ifp->if_flags; | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
break; | break; | ||||
case SIOCSDRVSPEC: | case SIOCSDRVSPEC: | ||||
case SIOCGDRVSPEC: | case SIOCGDRVSPEC: | ||||
IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific " | IOCTL_DEBUGOUT("ioctl: SIOCxDRVSPEC (Get/Set Driver-specific " | ||||
"Info)\n"); | "Info)\n"); | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | case SIOCSIFCAP: | ||||
} | } | ||||
VLAN_CAPABILITIES(ifp); | VLAN_CAPABILITIES(ifp); | ||||
break; | break; | ||||
} | } | ||||
#if __FreeBSD_version >= 1003000 | #if __FreeBSD_version >= 1003000 | ||||
case SIOCGI2C: | case SIOCGI2C: | ||||
{ | { | ||||
struct ifi2creq i2c; | |||||
int i; | |||||
IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); | IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); | ||||
if (!pf->has_i2c) | if (!pf->has_i2c) | ||||
return (ENOTTY); | return (ENOTTY); | ||||
error = copyin(ifr_data_get_ptr(ifr), &i2c, sizeof(i2c)); | error = ixl_handle_i2c_eeprom_read_cmd(pf, ifr); | ||||
if (error != 0) | |||||
break; | break; | ||||
if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { | |||||
error = EINVAL; | |||||
break; | |||||
} | } | ||||
if (i2c.len > sizeof(i2c.data)) { | |||||
error = EINVAL; | |||||
break; | |||||
} | |||||
for (i = 0; i < i2c.len; i++) | |||||
if (ixl_read_i2c_byte(pf, i2c.offset + i, | |||||
i2c.dev_addr, &i2c.data[i])) | |||||
return (EIO); | |||||
error = copyout(&i2c, ifr_data_get_ptr(ifr), sizeof(i2c)); | |||||
break; | |||||
} | |||||
#endif | #endif | ||||
default: | default: | ||||
IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); | IOCTL_DEBUGOUT("ioctl: UNKNOWN (0x%X)\n", (int)command); | ||||
error = ether_ioctl(ifp, command, data); | error = ether_ioctl(ifp, command, data); | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | ixl_phy_type_string(u32 bit_pos, bool ext) | ||||
}; | }; | ||||
static char * ext_phy_types_str[8] = { | static char * ext_phy_types_str[8] = { | ||||
"25GBASE-KR", | "25GBASE-KR", | ||||
"25GBASE-CR", | "25GBASE-CR", | ||||
"25GBASE-SR", | "25GBASE-SR", | ||||
"25GBASE-LR", | "25GBASE-LR", | ||||
"25GBASE-AOC", | "25GBASE-AOC", | ||||
"25GBASE-ACC", | "25GBASE-ACC", | ||||
"Reserved (6)", | "2.5GBASE-T", | ||||
"Reserved (7)" | "5GBASE-T" | ||||
}; | }; | ||||
if (ext && bit_pos > 7) return "Invalid_Ext"; | if (ext && bit_pos > 7) return "Invalid_Ext"; | ||||
if (bit_pos > 31) return "Invalid"; | if (bit_pos > 31) return "Invalid"; | ||||
return (ext) ? ext_phy_types_str[bit_pos] : phy_types_str[bit_pos]; | return (ext) ? ext_phy_types_str[bit_pos] : phy_types_str[bit_pos]; | ||||
} | } | ||||
static char * | |||||
ixl_phy_type_string_ls(u8 val) | |||||
{ | |||||
if (val >= 0x1F) | |||||
return ixl_phy_type_string(val - 0x1F, true); | |||||
else | |||||
return ixl_phy_type_string(val, false); | |||||
} | |||||
int | int | ||||
ixl_aq_get_link_status(struct ixl_pf *pf, struct i40e_aqc_get_link_status *link_status) | ixl_aq_get_link_status(struct ixl_pf *pf, struct i40e_aqc_get_link_status *link_status) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct i40e_aq_desc desc; | struct i40e_aq_desc desc; | ||||
enum i40e_status_code status; | enum i40e_status_code status; | ||||
Show All 10 Lines | device_printf(dev, | ||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | i40e_aq_str(hw, hw->aq.asq_last_status)); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
bcopy(aq_link_status, link_status, sizeof(struct i40e_aqc_get_link_status)); | bcopy(aq_link_status, link_status, sizeof(struct i40e_aqc_get_link_status)); | ||||
return (0); | return (0); | ||||
} | } | ||||
static char * | |||||
ixl_phy_type_string_ls(u8 val) | |||||
{ | |||||
if (val >= 0x1F) | |||||
return ixl_phy_type_string(val - 0x1F, true); | |||||
else | |||||
return ixl_phy_type_string(val, false); | |||||
} | |||||
static int | static int | ||||
ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) | ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | struct ixl_pf *pf = (struct ixl_pf *)arg1; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct sbuf *buf; | struct sbuf *buf; | ||||
int error = 0; | int error = 0; | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | sbuf_printf(buf, "\n" | ||||
"PHY Type : %08x", | "PHY Type : %08x", | ||||
abilities.phy_type); | abilities.phy_type); | ||||
if (abilities.phy_type != 0) { | if (abilities.phy_type != 0) { | ||||
sbuf_printf(buf, "<"); | sbuf_printf(buf, "<"); | ||||
for (int i = 0; i < 32; i++) | for (int i = 0; i < 32; i++) | ||||
if ((1 << i) & abilities.phy_type) | if ((1 << i) & abilities.phy_type) | ||||
sbuf_printf(buf, "%s,", ixl_phy_type_string(i, false)); | sbuf_printf(buf, "%s,", ixl_phy_type_string(i, false)); | ||||
sbuf_printf(buf, ">\n"); | sbuf_printf(buf, ">"); | ||||
} | } | ||||
sbuf_printf(buf, "PHY Ext : %02x", | sbuf_printf(buf, "\nPHY Ext : %02x", | ||||
abilities.phy_type_ext); | abilities.phy_type_ext); | ||||
if (abilities.phy_type_ext != 0) { | if (abilities.phy_type_ext != 0) { | ||||
sbuf_printf(buf, "<"); | sbuf_printf(buf, "<"); | ||||
for (int i = 0; i < 4; i++) | for (int i = 0; i < 4; i++) | ||||
if ((1 << i) & abilities.phy_type_ext) | if ((1 << i) & abilities.phy_type_ext) | ||||
sbuf_printf(buf, "%s,", ixl_phy_type_string(i, true)); | sbuf_printf(buf, "%s,", | ||||
ixl_phy_type_string(i, true)); | |||||
sbuf_printf(buf, ">"); | sbuf_printf(buf, ">"); | ||||
} | } | ||||
sbuf_printf(buf, "\n"); | |||||
sbuf_printf(buf, | sbuf_printf(buf, "\nSpeed : %02x", abilities.link_speed); | ||||
"Speed : %02x\n" | if (abilities.link_speed != 0) { | ||||
u8 link_speed; | |||||
sbuf_printf(buf, " <"); | |||||
for (int i = 0; i < 8; i++) { | |||||
link_speed = (1 << i) & abilities.link_speed; | |||||
if (link_speed) | |||||
sbuf_printf(buf, "%s, ", | |||||
ixl_link_speed_string(link_speed)); | |||||
} | |||||
sbuf_printf(buf, ">"); | |||||
} | |||||
sbuf_printf(buf, "\n" | |||||
"Abilities: %02x\n" | "Abilities: %02x\n" | ||||
"EEE cap : %04x\n" | "EEE cap : %04x\n" | ||||
"EEER reg : %08x\n" | "EEER reg : %08x\n" | ||||
"D3 Lpan : %02x\n" | "D3 Lpan : %02x\n" | ||||
"ID : %02x %02x %02x %02x\n" | "ID : %02x %02x %02x %02x\n" | ||||
"ModType : %02x %02x %02x\n" | "ModType : %02x %02x %02x\n" | ||||
"ModType E: %01x\n" | "ModType E: %01x\n" | ||||
"FEC Cfg : %02x\n" | "FEC Cfg : %02x\n" | ||||
"Ext CC : %02x", | "Ext CC : %02x", | ||||
abilities.link_speed, | |||||
abilities.abilities, abilities.eee_capability, | abilities.abilities, abilities.eee_capability, | ||||
abilities.eeer_val, abilities.d3_lpan, | abilities.eeer_val, abilities.d3_lpan, | ||||
abilities.phy_id[0], abilities.phy_id[1], | abilities.phy_id[0], abilities.phy_id[1], | ||||
abilities.phy_id[2], abilities.phy_id[3], | abilities.phy_id[2], abilities.phy_id[3], | ||||
abilities.module_type[0], abilities.module_type[1], | abilities.module_type[0], abilities.module_type[1], | ||||
abilities.module_type[2], (abilities.fec_cfg_curr_mod_ext_info & 0xe0) >> 5, | abilities.module_type[2], (abilities.fec_cfg_curr_mod_ext_info & 0xe0) >> 5, | ||||
abilities.fec_cfg_curr_mod_ext_info & 0x1F, | abilities.fec_cfg_curr_mod_ext_info & 0x1F, | ||||
abilities.ext_comp_code); | abilities.ext_comp_code); | ||||
▲ Show 20 Lines • Show All 471 Lines • ▼ Show 20 Lines | device_printf(dev, | ||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | i40e_aq_str(hw, hw->aq.asq_last_status)); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Read some diagnostic data from a (Q)SFP+ module | |||||
* | |||||
* SFP A2 QSFP Lower Page | |||||
* Temperature 96-97 22-23 | |||||
* Vcc 98-99 26-27 | |||||
* TX power 102-103 34-35..40-41 | |||||
* RX power 104-105 50-51..56-57 | |||||
*/ | |||||
static int | |||||
ixl_sysctl_read_i2c_diag_data(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
device_t dev = pf->dev; | |||||
struct sbuf *sbuf; | |||||
int error = 0; | |||||
u8 output; | |||||
if (req->oldptr == NULL) { | |||||
error = SYSCTL_OUT(req, 0, 128); | |||||
return (0); | |||||
} | |||||
error = pf->read_i2c_byte(pf, 0, 0xA0, &output); | |||||
if (error) { | |||||
device_printf(dev, "Error reading from i2c\n"); | |||||
return (error); | |||||
} | |||||
/* 0x3 for SFP; 0xD/0x11 for QSFP+/QSFP28 */ | |||||
if (output == 0x3) { | |||||
/* | |||||
* Check for: | |||||
* - Internally calibrated data | |||||
* - Diagnostic monitoring is implemented | |||||
*/ | |||||
pf->read_i2c_byte(pf, 92, 0xA0, &output); | |||||
if (!(output & 0x60)) { | |||||
device_printf(dev, "Module doesn't support diagnostics: %02X\n", output); | |||||
return (0); | |||||
} | |||||
sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req); | |||||
for (u8 offset = 96; offset < 100; offset++) { | |||||
pf->read_i2c_byte(pf, offset, 0xA2, &output); | |||||
sbuf_printf(sbuf, "%02X ", output); | |||||
} | |||||
for (u8 offset = 102; offset < 106; offset++) { | |||||
pf->read_i2c_byte(pf, offset, 0xA2, &output); | |||||
sbuf_printf(sbuf, "%02X ", output); | |||||
} | |||||
} else if (output == 0xD || output == 0x11) { | |||||
/* | |||||
* QSFP+ modules are always internally calibrated, and must indicate | |||||
* what types of diagnostic monitoring are implemented | |||||
*/ | |||||
sbuf = sbuf_new_for_sysctl(NULL, NULL, 128, req); | |||||
for (u8 offset = 22; offset < 24; offset++) { | |||||
pf->read_i2c_byte(pf, offset, 0xA0, &output); | |||||
sbuf_printf(sbuf, "%02X ", output); | |||||
} | |||||
for (u8 offset = 26; offset < 28; offset++) { | |||||
pf->read_i2c_byte(pf, offset, 0xA0, &output); | |||||
sbuf_printf(sbuf, "%02X ", output); | |||||
} | |||||
/* Read the data from the first lane */ | |||||
for (u8 offset = 34; offset < 36; offset++) { | |||||
pf->read_i2c_byte(pf, offset, 0xA0, &output); | |||||
sbuf_printf(sbuf, "%02X ", output); | |||||
} | |||||
for (u8 offset = 50; offset < 52; offset++) { | |||||
pf->read_i2c_byte(pf, offset, 0xA0, &output); | |||||
sbuf_printf(sbuf, "%02X ", output); | |||||
} | |||||
} else { | |||||
device_printf(dev, "Module is not SFP/SFP+/SFP28/QSFP+ (%02X)\n", output); | |||||
return (0); | |||||
} | |||||
sbuf_finish(sbuf); | |||||
sbuf_delete(sbuf); | |||||
return (0); | |||||
} | |||||
/* | |||||
* Sysctl to read a byte from I2C bus. | * Sysctl to read a byte from I2C bus. | ||||
* | * | ||||
* Input: 32-bit value: | * Input: 32-bit value: | ||||
* bits 0-7: device address (0xA0 or 0xA2) | * bits 0-7: device address (0xA0 or 0xA2) | ||||
* bits 8-15: offset (0-255) | * bits 8-15: offset (0-255) | ||||
* bits 16-31: unused | * bits 16-31: unused | ||||
* Output: 8-bit value read | * Output: 8-bit value read | ||||
*/ | */ | ||||
static int | static int | ||||
ixl_sysctl_read_i2c_byte(SYSCTL_HANDLER_ARGS) | ixl_sysctl_read_i2c_byte(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | struct ixl_pf *pf = (struct ixl_pf *)arg1; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
int input = -1, error = 0; | int input = -1, error = 0; | ||||
device_printf(dev, "%s: start\n", __func__); | |||||
u8 dev_addr, offset, output; | u8 dev_addr, offset, output; | ||||
/* Read in I2C read parameters */ | /* Read in I2C read parameters */ | ||||
error = sysctl_handle_int(oidp, &input, 0, req); | error = sysctl_handle_int(oidp, &input, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
/* Validate device address */ | /* Validate device address */ | ||||
dev_addr = input & 0xFF; | dev_addr = input & 0xFF; | ||||
if (dev_addr != 0xA0 && dev_addr != 0xA2) { | if (dev_addr != 0xA0 && dev_addr != 0xA2) { | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
offset = (input >> 8) & 0xFF; | offset = (input >> 8) & 0xFF; | ||||
error = ixl_read_i2c_byte(pf, offset, dev_addr, &output); | error = pf->read_i2c_byte(pf, offset, dev_addr, &output); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
device_printf(dev, "%02X\n", output); | device_printf(dev, "%02X\n", output); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
Show All 22 Lines | ixl_sysctl_write_i2c_byte(SYSCTL_HANDLER_ARGS) | ||||
/* Validate device address */ | /* Validate device address */ | ||||
dev_addr = input & 0xFF; | dev_addr = input & 0xFF; | ||||
if (dev_addr != 0xA0 && dev_addr != 0xA2) { | if (dev_addr != 0xA0 && dev_addr != 0xA2) { | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
offset = (input >> 8) & 0xFF; | offset = (input >> 8) & 0xFF; | ||||
value = (input >> 16) & 0xFF; | value = (input >> 16) & 0xFF; | ||||
error = ixl_write_i2c_byte(pf, offset, dev_addr, value); | error = pf->write_i2c_byte(pf, offset, dev_addr, value); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
device_printf(dev, "%02X written\n", value); | device_printf(dev, "%02X written\n", value); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | if (!buf) { | ||||
device_printf(dev, "Could not allocate sbuf for output.\n"); | device_printf(dev, "Could not allocate sbuf for output.\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
u8 *final_buff; | u8 *final_buff; | ||||
/* This amount is only necessary if reading the entire cluster into memory */ | /* This amount is only necessary if reading the entire cluster into memory */ | ||||
#define IXL_FINAL_BUFF_SIZE (1280 * 1024) | #define IXL_FINAL_BUFF_SIZE (1280 * 1024) | ||||
final_buff = malloc(IXL_FINAL_BUFF_SIZE, M_DEVBUF, M_WAITOK); | final_buff = malloc(IXL_FINAL_BUFF_SIZE, M_DEVBUF, M_WAITOK); | ||||
if (final_buff == NULL) { | |||||
device_printf(dev, "Could not allocate memory for output.\n"); | |||||
goto out; | |||||
} | |||||
int final_buff_len = 0; | int final_buff_len = 0; | ||||
u8 cluster_id = 1; | u8 cluster_id = 1; | ||||
bool more = true; | bool more = true; | ||||
u8 dump_buf[4096]; | u8 dump_buf[4096]; | ||||
u16 curr_buff_size = 4096; | u16 curr_buff_size = 4096; | ||||
u8 curr_next_table = 0; | u8 curr_next_table = 0; | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | while (more) { | ||||
bzero(dump_buf, sizeof(dump_buf)); | bzero(dump_buf, sizeof(dump_buf)); | ||||
curr_next_table = ret_next_table; | curr_next_table = ret_next_table; | ||||
curr_next_index = ret_next_index; | curr_next_index = ret_next_index; | ||||
} | } | ||||
free_out: | free_out: | ||||
free(final_buff, M_DEVBUF); | free(final_buff, M_DEVBUF); | ||||
out: | |||||
error = sbuf_finish(buf); | error = sbuf_finish(buf); | ||||
if (error) | if (error) | ||||
device_printf(dev, "Error finishing sbuf: %d\n", error); | device_printf(dev, "Error finishing sbuf: %d\n", error); | ||||
sbuf_delete(buf); | sbuf_delete(buf); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
ixl_sysctl_fw_lldp(SYSCTL_HANDLER_ARGS) | ixl_start_fw_lldp(struct ixl_pf *pf) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
enum i40e_status_code status; | |||||
status = i40e_aq_start_lldp(hw, false, NULL); | |||||
if (status != I40E_SUCCESS) { | |||||
switch (hw->aq.asq_last_status) { | |||||
case I40E_AQ_RC_EEXIST: | |||||
device_printf(pf->dev, | |||||
"FW LLDP agent is already running\n"); | |||||
break; | |||||
case I40E_AQ_RC_EPERM: | |||||
device_printf(pf->dev, | |||||
"Device configuration forbids SW from starting " | |||||
"the LLDP agent. Set the \"LLDP Agent\" UEFI HII " | |||||
"attribute to \"Enabled\" to use this sysctl\n"); | |||||
return (EINVAL); | |||||
default: | |||||
device_printf(pf->dev, | |||||
"Starting FW LLDP agent failed: error: %s, %s\n", | |||||
i40e_stat_str(hw, status), | |||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | |||||
return (EINVAL); | |||||
} | |||||
} | |||||
atomic_clear_int(&pf->state, IXL_PF_STATE_FW_LLDP_DISABLED); | |||||
return (0); | |||||
} | |||||
static int | |||||
ixl_stop_fw_lldp(struct ixl_pf *pf) | |||||
{ | |||||
struct i40e_hw *hw = &pf->hw; | |||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
int error = 0; | |||||
int state, new_state; | |||||
enum i40e_status_code status; | enum i40e_status_code status; | ||||
if (hw->func_caps.npar_enable != 0) { | |||||
device_printf(dev, | |||||
"Disabling FW LLDP agent is not supported on this device\n"); | |||||
return (EINVAL); | |||||
} | |||||
if ((hw->flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE) == 0) { | |||||
device_printf(dev, | |||||
"Disabling FW LLDP agent is not supported in this FW version. Please update FW to enable this feature.\n"); | |||||
return (EINVAL); | |||||
} | |||||
status = i40e_aq_stop_lldp(hw, true, false, NULL); | |||||
if (status != I40E_SUCCESS) { | |||||
if (hw->aq.asq_last_status != I40E_AQ_RC_EPERM) { | |||||
device_printf(dev, | |||||
"Disabling FW LLDP agent failed: error: %s, %s\n", | |||||
i40e_stat_str(hw, status), | |||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | |||||
return (EINVAL); | |||||
} | |||||
device_printf(dev, "FW LLDP agent is already stopped\n"); | |||||
} | |||||
i40e_aq_set_dcb_parameters(hw, true, NULL); | |||||
atomic_set_int(&pf->state, IXL_PF_STATE_FW_LLDP_DISABLED); | |||||
return (0); | |||||
} | |||||
static int | |||||
ixl_sysctl_fw_lldp(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
int state, new_state, error = 0; | |||||
state = new_state = ((pf->state & IXL_PF_STATE_FW_LLDP_DISABLED) == 0); | state = new_state = ((pf->state & IXL_PF_STATE_FW_LLDP_DISABLED) == 0); | ||||
/* Read in new mode */ | /* Read in new mode */ | ||||
error = sysctl_handle_int(oidp, &new_state, 0, req); | error = sysctl_handle_int(oidp, &new_state, 0, req); | ||||
if ((error) || (req->newptr == NULL)) | if ((error) || (req->newptr == NULL)) | ||||
return (error); | return (error); | ||||
/* Already in requested state */ | /* Already in requested state */ | ||||
if (new_state == state) | if (new_state == state) | ||||
return (error); | return (error); | ||||
if (new_state == 0) { | if (new_state == 0) | ||||
if (hw->mac.type == I40E_MAC_X722 || hw->func_caps.npar_enable != 0) { | return ixl_stop_fw_lldp(pf); | ||||
device_printf(dev, "Disabling FW LLDP agent is not supported on this device\n"); | |||||
return (EINVAL); | |||||
} | |||||
if (pf->hw.aq.api_maj_ver < 1 || | return ixl_start_fw_lldp(pf); | ||||
(pf->hw.aq.api_maj_ver == 1 && | |||||
pf->hw.aq.api_min_ver < 7)) { | |||||
device_printf(dev, "Disabling FW LLDP agent is not supported in this FW version. Please update FW to enable this feature.\n"); | |||||
return (EINVAL); | |||||
} | } | ||||
i40e_aq_stop_lldp(&pf->hw, true, NULL); | static int | ||||
i40e_aq_set_dcb_parameters(&pf->hw, true, NULL); | ixl_sysctl_eee_enable(SYSCTL_HANDLER_ARGS) | ||||
atomic_set_int(&pf->state, IXL_PF_STATE_FW_LLDP_DISABLED); | { | ||||
} else { | struct ixl_pf *pf = (struct ixl_pf *)arg1; | ||||
status = i40e_aq_start_lldp(&pf->hw, NULL); | int state, new_state; | ||||
if (status != I40E_SUCCESS && hw->aq.asq_last_status == I40E_AQ_RC_EEXIST) | int sysctl_handle_status = 0; | ||||
device_printf(dev, "FW LLDP agent is already running\n"); | enum i40e_status_code cmd_status; | ||||
atomic_clear_int(&pf->state, IXL_PF_STATE_FW_LLDP_DISABLED); | |||||
} | |||||
return (0); | /* Init states' values */ | ||||
} | state = new_state = (!!(pf->state & IXL_PF_STATE_EEE_ENABLED)); | ||||
/* | /* Get requested mode */ | ||||
* Get FW LLDP Agent status | sysctl_handle_status = sysctl_handle_int(oidp, &new_state, 0, req); | ||||
*/ | if ((sysctl_handle_status) || (req->newptr == NULL)) | ||||
int | return (sysctl_handle_status); | ||||
ixl_get_fw_lldp_status(struct ixl_pf *pf) | |||||
{ | |||||
enum i40e_status_code ret = I40E_SUCCESS; | |||||
struct i40e_lldp_variables lldp_cfg; | |||||
struct i40e_hw *hw = &pf->hw; | |||||
u8 adminstatus = 0; | |||||
ret = i40e_read_lldp_cfg(hw, &lldp_cfg); | /* Check if state has changed */ | ||||
if (ret) | if (new_state == state) | ||||
return ret; | return (0); | ||||
/* Get the LLDP AdminStatus for the current port */ | /* Set new state */ | ||||
adminstatus = lldp_cfg.adminstatus >> (hw->port * 4); | cmd_status = i40e_enable_eee(&pf->hw, (bool)(!!new_state)); | ||||
adminstatus &= 0xf; | |||||
/* Check if LLDP agent is disabled */ | /* Save new state or report error */ | ||||
if (!adminstatus) { | if (!cmd_status) { | ||||
device_printf(pf->dev, "FW LLDP agent is disabled for this PF.\n"); | if (new_state == 0) | ||||
atomic_set_int(&pf->state, IXL_PF_STATE_FW_LLDP_DISABLED); | atomic_clear_int(&pf->state, IXL_PF_STATE_EEE_ENABLED); | ||||
} else | else | ||||
atomic_clear_int(&pf->state, IXL_PF_STATE_FW_LLDP_DISABLED); | atomic_set_int(&pf->state, IXL_PF_STATE_EEE_ENABLED); | ||||
} else if (cmd_status == I40E_ERR_CONFIG) | |||||
return (EPERM); | |||||
else | |||||
return (EIO); | |||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
ixl_attach_get_link_status(struct ixl_pf *pf) | ixl_attach_get_link_status(struct ixl_pf *pf) | ||||
{ | { | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
Show All 19 Lines |