Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/ixl/ixl_pf_main.c
Show All 33 Lines | |||||
#include "ixl_pf.h" | #include "ixl_pf.h" | ||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
#include "ixl_pf_iov.h" | #include "ixl_pf_iov.h" | ||||
#endif | #endif | ||||
#ifdef IXL_IW | |||||
#include "ixl_iw.h" | |||||
#include "ixl_iw_int.h" | |||||
#endif | |||||
#ifdef DEV_NETMAP | #ifdef DEV_NETMAP | ||||
#include <net/netmap.h> | #include <net/netmap.h> | ||||
#include <sys/selinfo.h> | #include <sys/selinfo.h> | ||||
#include <dev/netmap/netmap_kern.h> | #include <dev/netmap/netmap_kern.h> | ||||
#endif /* DEV_NETMAP */ | #endif /* DEV_NETMAP */ | ||||
static int ixl_setup_queue(struct ixl_queue *, struct ixl_pf *, int); | static int ixl_setup_queue(struct ixl_queue *, struct ixl_pf *, int); | ||||
static u64 ixl_max_aq_speed_to_value(u8); | |||||
static u8 ixl_convert_sysctl_aq_link_speed(u8, bool); | |||||
/* Sysctls */ | /* Sysctls */ | ||||
static int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS); | static int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_set_advertise(SYSCTL_HANDLER_ARGS); | static int ixl_set_advertise(SYSCTL_HANDLER_ARGS); | ||||
static int ixl_current_speed(SYSCTL_HANDLER_ARGS); | static int ixl_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); | ||||
/* 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_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_read_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_rs_ability(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_auto_enable(SYSCTL_HANDLER_ARGS); | |||||
#ifdef IXL_DEBUG | |||||
static int ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS); | |||||
static int ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS); | |||||
#endif | |||||
#ifdef IXL_IW | |||||
extern int ixl_enable_iwarp; | |||||
#endif | |||||
void | void | ||||
ixl_dbg(struct ixl_pf *pf, enum ixl_dbg_mask mask, char *fmt, ...) | ixl_debug_core(struct ixl_pf *pf, enum ixl_dbg_mask mask, char *fmt, ...) | ||||
{ | { | ||||
va_list args; | va_list args; | ||||
if (!(mask & pf->dbg_mask)) | if (!(mask & pf->dbg_mask)) | ||||
return; | return; | ||||
/* Re-implement device_printf() */ | |||||
device_print_prettyname(pf->dev); | |||||
va_start(args, fmt); | va_start(args, fmt); | ||||
device_printf(pf->dev, fmt, args); | vprintf(fmt, args); | ||||
va_end(args); | va_end(args); | ||||
} | } | ||||
/* | /* | ||||
** Put the FW, API, NVM, EEtrackID, and OEM version information into a string | ** Put the FW, API, NVM, EEtrackID, and OEM version information into a string | ||||
*/ | */ | ||||
void | void | ||||
ixl_nvm_version_str(struct i40e_hw *hw, struct sbuf *buf) | ixl_nvm_version_str(struct i40e_hw *hw, struct sbuf *buf) | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | 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]; | u8 tmpaddr[ETHER_ADDR_LEN]; | ||||
int ret; | int ret; | ||||
mtx_assert(&pf->pf_mtx, MA_OWNED); | |||||
INIT_DEBUGOUT("ixl_init_locked: begin"); | INIT_DEBUGOUT("ixl_init_locked: begin"); | ||||
IXL_PF_LOCK_ASSERT(pf); | |||||
ixl_stop_locked(pf); | ixl_stop_locked(pf); | ||||
/* | |||||
* If the aq is dead here, it probably means something outside of the driver | |||||
* did something to the adapter, like a PF reset. | |||||
* So rebuild the driver's state here if that occurs. | |||||
*/ | |||||
if (!i40e_check_asq_alive(&pf->hw)) { | |||||
device_printf(dev, "Admin Queue is down; resetting...\n"); | |||||
ixl_teardown_hw_structs(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, | bcopy(IF_LLADDR(vsi->ifp), tmpaddr, | ||||
I40E_ETH_LENGTH_OF_ADDRESS); | I40E_ETH_LENGTH_OF_ADDRESS); | ||||
if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && | if (!cmp_etheraddr(hw->mac.addr, tmpaddr) && | ||||
(i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { | (i40e_validate_mac_addr(tmpaddr) == I40E_SUCCESS)) { | ||||
ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); | ixl_del_filter(vsi, hw->mac.addr, IXL_VLAN_ANY); | ||||
bcopy(tmpaddr, hw->mac.addr, | bcopy(tmpaddr, hw->mac.addr, | ||||
I40E_ETH_LENGTH_OF_ADDRESS); | I40E_ETH_LENGTH_OF_ADDRESS); | ||||
Show All 38 Lines | ixl_init_locked(struct ixl_pf *pf) | ||||
/* Add protocol filters to list */ | /* Add protocol filters to list */ | ||||
ixl_init_filters(vsi); | ixl_init_filters(vsi); | ||||
/* Setup vlan's if needed */ | /* Setup vlan's if needed */ | ||||
ixl_setup_vlan_filters(vsi); | 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->enable_msix) { | 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); | ||||
/* 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); | ||||
/* Set initial advertised speed sysctl value */ | |||||
ixl_get_initial_advertised_speeds(pf); | |||||
/* Start the local timer */ | /* Start the local timer */ | ||||
callout_reset(&pf->timer, hz, ixl_local_timer, pf); | 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 | |||||
if (ixl_enable_iwarp && pf->iw_enabled) { | |||||
ret = ixl_iw_pf_init(pf); | |||||
if (ret) | |||||
device_printf(dev, | |||||
"initialize iwarp failed, code %d\n", ret); | |||||
} | } | ||||
#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) | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | #endif | ||||
/* 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) ? "MDIO dedicated" : | (hw->func_caps.mdio_port_mode == 1) ? "MDIO dedicated" : | ||||
"MDIO shared"); | "MDIO shared"); | ||||
struct i40e_osdep *osdep = (struct i40e_osdep *)hw->back; | |||||
osdep->i2c_intfc_num = ixl_find_i2c_interface(pf); | |||||
if (osdep->i2c_intfc_num != -1) | |||||
pf->has_i2c = true; | |||||
return (error); | return (error); | ||||
} | } | ||||
void | void | ||||
ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) | ixl_cap_txcsum_tso(struct ixl_vsi *vsi, struct ifnet *ifp, int mask) | ||||
{ | { | ||||
device_t dev = vsi->dev; | device_t dev = vsi->dev; | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | status = i40e_aq_get_phy_capabilities(hw, FALSE, false, &abilities, | ||||
NULL); | NULL); | ||||
if (status) { | if (status) { | ||||
/* Non-fatal error */ | /* Non-fatal error */ | ||||
device_printf(dev, "%s: i40e_aq_get_phy_capabilities() error %d\n", | device_printf(dev, "%s: i40e_aq_get_phy_capabilities() error %d\n", | ||||
__func__, status); | __func__, status); | ||||
return; | return; | ||||
} | } | ||||
if (abilities.link_speed & I40E_LINK_SPEED_40GB) | pf->advertised_speed = | ||||
pf->advertised_speed |= 0x10; | ixl_convert_sysctl_aq_link_speed(abilities.link_speed, false); | ||||
if (abilities.link_speed & I40E_LINK_SPEED_20GB) | |||||
pf->advertised_speed |= 0x8; | |||||
if (abilities.link_speed & I40E_LINK_SPEED_10GB) | |||||
pf->advertised_speed |= 0x4; | |||||
if (abilities.link_speed & I40E_LINK_SPEED_1GB) | |||||
pf->advertised_speed |= 0x2; | |||||
if (abilities.link_speed & I40E_LINK_SPEED_100MB) | |||||
pf->advertised_speed |= 0x1; | |||||
} | } | ||||
int | int | ||||
ixl_teardown_hw_structs(struct ixl_pf *pf) | ixl_teardown_hw_structs(struct ixl_pf *pf) | ||||
{ | { | ||||
enum i40e_status_code status = 0; | enum i40e_status_code status = 0; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | |||||
ixl_intr(void *arg) | ixl_intr(void *arg) | ||||
{ | { | ||||
struct ixl_pf *pf = arg; | struct ixl_pf *pf = 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 reg, icr0, mask; | u32 icr0; | ||||
bool more_tx, more_rx; | bool more_tx, more_rx; | ||||
++que->irqs; | pf->admin_irq++; | ||||
/* Protect against spurious interrupts */ | /* Protect against spurious interrupts */ | ||||
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | ||||
return; | return; | ||||
icr0 = rd32(hw, I40E_PFINT_ICR0); | icr0 = rd32(hw, I40E_PFINT_ICR0); | ||||
reg = rd32(hw, I40E_PFINT_DYN_CTL0); | |||||
reg = reg | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; | |||||
wr32(hw, I40E_PFINT_DYN_CTL0, reg); | |||||
mask = rd32(hw, I40E_PFINT_ICR0_ENA); | |||||
#ifdef PCI_IOV | #ifdef PCI_IOV | ||||
if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) | if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) | ||||
taskqueue_enqueue(pf->tq, &pf->vflr_task); | taskqueue_enqueue(pf->tq, &pf->vflr_task); | ||||
#endif | #endif | ||||
if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { | if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) { | ||||
taskqueue_enqueue(pf->tq, &pf->adminq); | taskqueue_enqueue(pf->tq, &pf->adminq); | ||||
return; | |||||
} | } | ||||
if (icr0 & I40E_PFINT_ICR0_QUEUE_0_MASK) { | |||||
++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); | ||||
if (!drbr_empty(vsi->ifp, txr->br)) | if (!drbr_empty(vsi->ifp, txr->br)) | ||||
more_tx = 1; | more_tx = 1; | ||||
IXL_TX_UNLOCK(txr); | IXL_TX_UNLOCK(txr); | ||||
} | |||||
/* re-enable other interrupt causes */ | ixl_enable_intr0(hw); | ||||
wr32(hw, I40E_PFINT_ICR0_ENA, mask); | |||||
/* And now the queues */ | |||||
reg = rd32(hw, I40E_QINT_RQCTL(0)); | |||||
reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; | |||||
wr32(hw, I40E_QINT_RQCTL(0), reg); | |||||
reg = rd32(hw, I40E_QINT_TQCTL(0)); | |||||
reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; | |||||
reg &= ~I40E_PFINT_ICR0_INTEVENT_MASK; | |||||
wr32(hw, I40E_QINT_TQCTL(0), reg); | |||||
ixl_enable_legacy(hw); | |||||
return; | |||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* MSIX VSI Interrupt Service routine | * MSIX VSI Interrupt Service routine | ||||
* | * | ||||
**********************************************************************/ | **********************************************************************/ | ||||
▲ Show 20 Lines • Show All 117 Lines • ▼ Show 20 Lines | if (reg & I40E_PFINT_ICR0_VFLR_MASK) { | ||||
mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; | mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK; | ||||
taskqueue_enqueue(pf->tq, &pf->vflr_task); | taskqueue_enqueue(pf->tq, &pf->vflr_task); | ||||
} | } | ||||
#endif | #endif | ||||
if (do_task) | if (do_task) | ||||
taskqueue_enqueue(pf->tq, &pf->adminq); | taskqueue_enqueue(pf->tq, &pf->adminq); | ||||
else | else | ||||
ixl_enable_adminq(hw); | ixl_enable_intr0(hw); | ||||
} | } | ||||
void | void | ||||
ixl_set_promisc(struct ixl_vsi *vsi) | ixl_set_promisc(struct ixl_vsi *vsi) | ||||
{ | { | ||||
struct ifnet *ifp = vsi->ifp; | struct ifnet *ifp = vsi->ifp; | ||||
struct i40e_hw *hw = vsi->hw; | struct i40e_hw *hw = vsi->hw; | ||||
int err, mcnt = 0; | int err, mcnt = 0; | ||||
▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
ixl_local_timer(void *arg) | ixl_local_timer(void *arg) | ||||
{ | { | ||||
struct ixl_pf *pf = arg; | struct ixl_pf *pf = 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; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct tx_ring *txr; | |||||
int hung = 0; | int hung = 0; | ||||
u32 mask; | u32 mask; | ||||
s32 timer, new_timer; | |||||
mtx_assert(&pf->pf_mtx, MA_OWNED); | 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); | ||||
/* Update stats */ | /* Update stats */ | ||||
ixl_update_stats_counters(pf); | ixl_update_stats_counters(pf); | ||||
/* Check status of the queues */ | /* Check status of the queues */ | ||||
mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | | mask = (I40E_PFINT_DYN_CTLN_INTENA_MASK | | ||||
I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK); | I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK | | ||||
I40E_PFINT_DYN_CTLN_ITR_INDX_MASK); | |||||
for (int i = 0; i < vsi->num_queues; i++, que++) { | for (int i = 0; i < vsi->num_queues; i++, que++) { | ||||
/* Any queues with outstanding work get a sw irq */ | txr = &que->txr; | ||||
if (que->busy) | timer = atomic_load_acq_32(&txr->watchdog_timer); | ||||
wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); | if (timer > 0) { | ||||
new_timer = timer - hz; | |||||
if (new_timer <= 0) { | |||||
atomic_store_rel_32(&txr->watchdog_timer, -1); | |||||
device_printf(dev, "WARNING: queue %d " | |||||
"appears to be hung!\n", que->me); | |||||
++hung; | |||||
} else { | |||||
/* | /* | ||||
** Each time txeof runs without cleaning, but there | * If this fails, that means something in the TX path has updated | ||||
** are uncleaned descriptors it increments busy. If | * the watchdog, so it means the TX path is still working and | ||||
** we get to 5 we declare it hung. | * the watchdog doesn't need to countdown. | ||||
*/ | */ | ||||
if (que->busy == IXL_QUEUE_HUNG) { | atomic_cmpset_rel_32(&txr->watchdog_timer, timer, new_timer); | ||||
++hung; | /* Any queues with outstanding work get a sw irq */ | ||||
continue; | wr32(hw, I40E_PFINT_DYN_CTLN(que->me), mask); | ||||
} | } | ||||
if (que->busy >= IXL_MAX_TX_BUSY) { | |||||
#ifdef IXL_DEBUG | |||||
device_printf(dev, "Warning queue %d " | |||||
"appears to be hung!\n", i); | |||||
#endif | |||||
que->busy = IXL_QUEUE_HUNG; | |||||
++hung; | |||||
} | } | ||||
} | } | ||||
/* Only reinit if all queues show hung */ | /* Reset when a queue shows hung */ | ||||
if (hung == vsi->num_queues) | if (hung) | ||||
goto hung; | goto hung; | ||||
callout_reset(&pf->timer, hz, ixl_local_timer, pf); | callout_reset(&pf->timer, hz, ixl_local_timer, pf); | ||||
return; | return; | ||||
hung: | hung: | ||||
device_printf(dev, "Local Timer: HANG DETECT - Resetting!!\n"); | device_printf(dev, "WARNING: Resetting!\n"); | ||||
pf->watchdog_events++; | |||||
ixl_init_locked(pf); | ixl_init_locked(pf); | ||||
} | } | ||||
void | |||||
ixl_link_up_msg(struct ixl_pf *pf) | |||||
{ | |||||
struct i40e_hw *hw = &pf->hw; | |||||
struct ifnet *ifp = pf->vsi.ifp; | |||||
log(LOG_NOTICE, "%s: Link is up, %s Full Duplex, FEC: %s, Autoneg: %s, Flow Control: %s\n", | |||||
ifp->if_xname, | |||||
ixl_aq_speed_to_str(hw->phy.link_info.link_speed), | |||||
(hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_KR_ENA) ? | |||||
"Clause 74 BASE-R FEC" : (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_RS_ENA) ? | |||||
"Clause 108 RS-FEC" : "None", | |||||
(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_RX) ? | |||||
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[1] : ixl_fc_string[0]); | |||||
} | |||||
/* | /* | ||||
** Note: this routine updates the OS on the link state | ** Note: this routine updates the OS on the link state | ||||
** the real check of the hardware only happens with | ** the real check of the hardware only happens with | ||||
** a link interrupt. | ** a link interrupt. | ||||
*/ | */ | ||||
void | void | ||||
ixl_update_link_status(struct ixl_pf *pf) | ixl_update_link_status(struct ixl_pf *pf) | ||||
{ | { | ||||
struct ixl_vsi *vsi = &pf->vsi; | struct ixl_vsi *vsi = &pf->vsi; | ||||
struct i40e_hw *hw = &pf->hw; | |||||
struct ifnet *ifp = vsi->ifp; | struct ifnet *ifp = vsi->ifp; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
if (pf->link_up) { | if (pf->link_up) { | ||||
if (vsi->link_active == FALSE) { | if (vsi->link_active == FALSE) { | ||||
pf->fc = hw->fc.current_mode; | |||||
if (bootverbose) { | |||||
device_printf(dev, "Link is up %d Gbps %s," | |||||
" Flow Control: %s\n", | |||||
((pf->link_speed == | |||||
I40E_LINK_SPEED_40GB)? 40:10), | |||||
"Full Duplex", ixl_fc_string[pf->fc]); | |||||
} | |||||
vsi->link_active = TRUE; | vsi->link_active = TRUE; | ||||
ifp->if_baudrate = ixl_max_aq_speed_to_value(pf->link_speed); | |||||
if_link_state_change(ifp, LINK_STATE_UP); | if_link_state_change(ifp, LINK_STATE_UP); | ||||
ixl_link_up_msg(pf); | |||||
} | } | ||||
} else { /* Link down */ | } else { /* Link down */ | ||||
if (vsi->link_active == TRUE) { | if (vsi->link_active == TRUE) { | ||||
if (bootverbose) | if (bootverbose) | ||||
device_printf(dev, "Link is Down\n"); | device_printf(dev, "Link is Down\n"); | ||||
if_link_state_change(ifp, LINK_STATE_DOWN); | if_link_state_change(ifp, LINK_STATE_DOWN); | ||||
vsi->link_active = FALSE; | vsi->link_active = FALSE; | ||||
} | } | ||||
Show All 14 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); | ||||
#ifdef IXL_IW | |||||
/* Stop iWARP device */ | |||||
if (ixl_enable_iwarp && pf->iw_enabled) | |||||
ixl_iw_pf_stop(pf); | |||||
#endif | |||||
/* Stop the local timer */ | /* Stop the local timer */ | ||||
callout_stop(&pf->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 */ | /* Tell the stack that the interface is no longer active */ | ||||
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING); | 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); | ||||
ixl_teardown_queue_msix(&pf->vsi); | |||||
ixl_free_queue_tqs(&pf->vsi); | |||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* Setup MSIX Interrupt resources and handlers for the VSI | * Setup MSIX Interrupt resources and handlers for the VSI | ||||
* | * | ||||
**********************************************************************/ | **********************************************************************/ | ||||
int | int | ||||
ixl_assign_vsi_legacy(struct ixl_pf *pf) | ixl_setup_legacy(struct ixl_pf *pf) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct ixl_vsi *vsi = &pf->vsi; | |||||
struct ixl_queue *que = vsi->queues; | |||||
int error, rid = 0; | int error, rid = 0; | ||||
if (pf->msix == 1) | if (pf->msix == 1) | ||||
rid = 1; | rid = 1; | ||||
pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, | pf->res = bus_alloc_resource_any(dev, SYS_RES_IRQ, | ||||
&rid, RF_SHAREABLE | RF_ACTIVE); | &rid, RF_SHAREABLE | RF_ACTIVE); | ||||
if (pf->res == NULL) { | if (pf->res == NULL) { | ||||
device_printf(dev, "Unable to allocate" | device_printf(dev, "bus_alloc_resource_any() for" | ||||
" bus resource: vsi legacy/msi interrupt\n"); | " legacy/msi interrupt\n"); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
/* Set the handler function */ | /* Set the handler function */ | ||||
error = bus_setup_intr(dev, pf->res, | error = bus_setup_intr(dev, pf->res, | ||||
INTR_TYPE_NET | INTR_MPSAFE, NULL, | INTR_TYPE_NET | INTR_MPSAFE, NULL, | ||||
ixl_intr, pf, &pf->tag); | ixl_intr, pf, &pf->tag); | ||||
if (error) { | if (error) { | ||||
pf->res = NULL; | pf->res = NULL; | ||||
device_printf(dev, "Failed to register legacy/msi handler\n"); | device_printf(dev, "bus_setup_intr() for legacy/msi" | ||||
return (error); | " interrupt handler failed, error %d\n", error); | ||||
return (ENXIO); | |||||
} | } | ||||
bus_describe_intr(dev, pf->res, pf->tag, "irq0"); | error = bus_describe_intr(dev, pf->res, pf->tag, "irq"); | ||||
TASK_INIT(&que->tx_task, 0, ixl_deferred_mq_start, que); | if (error) { | ||||
TASK_INIT(&que->task, 0, ixl_handle_que, que); | /* non-fatal */ | ||||
que->tq = taskqueue_create_fast("ixl_que", M_NOWAIT, | device_printf(dev, "bus_describe_intr() for Admin Queue" | ||||
taskqueue_thread_enqueue, &que->tq); | " interrupt name failed, error %d\n", error); | ||||
taskqueue_start_threads(&que->tq, 1, PI_NET, "%s que", | } | ||||
device_get_nameunit(dev)); | |||||
TASK_INIT(&pf->adminq, 0, ixl_do_adminq, pf); | |||||
pf->tq = taskqueue_create_fast("ixl_adm", M_NOWAIT, | |||||
taskqueue_thread_enqueue, &pf->tq); | |||||
taskqueue_start_threads(&pf->tq, 1, PI_NET, "%s adminq", | |||||
device_get_nameunit(dev)); | |||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
ixl_setup_adminq_tq(struct ixl_pf *pf) | ixl_setup_adminq_tq(struct ixl_pf *pf) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
int error = 0; | int error = 0; | ||||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | ixl_setup_adminq_msix(struct ixl_pf *pf) | ||||
if (error) { | if (error) { | ||||
pf->res = NULL; | pf->res = NULL; | ||||
device_printf(dev, "bus_setup_intr() for Admin Queue" | device_printf(dev, "bus_setup_intr() for Admin Queue" | ||||
" interrupt handler failed, error %d\n", error); | " interrupt handler failed, error %d\n", error); | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
error = bus_describe_intr(dev, pf->res, pf->tag, "aq"); | error = bus_describe_intr(dev, pf->res, pf->tag, "aq"); | ||||
if (error) { | if (error) { | ||||
/* Probably non-fatal? */ | /* non-fatal */ | ||||
device_printf(dev, "bus_describe_intr() for Admin Queue" | device_printf(dev, "bus_describe_intr() for Admin Queue" | ||||
" interrupt name failed, error %d\n", error); | " interrupt name failed, error %d\n", error); | ||||
} | } | ||||
pf->admvec = 0; | pf->admvec = 0; | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 25 Lines | for (int i = 0; i < vsi->num_queues; i++, vector++, que++) { | ||||
/* Set the handler function */ | /* Set the handler function */ | ||||
error = bus_setup_intr(dev, que->res, | error = bus_setup_intr(dev, que->res, | ||||
INTR_TYPE_NET | INTR_MPSAFE, NULL, | INTR_TYPE_NET | INTR_MPSAFE, NULL, | ||||
ixl_msix_que, que, &que->tag); | ixl_msix_que, que, &que->tag); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "bus_setup_intr() for Queue %d" | device_printf(dev, "bus_setup_intr() for Queue %d" | ||||
" interrupt handler failed, error %d\n", | " interrupt handler failed, error %d\n", | ||||
que->me, error); | que->me, error); | ||||
bus_release_resource(dev, SYS_RES_IRQ, rid, que->res); | |||||
return (error); | return (error); | ||||
} | } | ||||
error = bus_describe_intr(dev, que->res, que->tag, "q%d", i); | error = bus_describe_intr(dev, que->res, que->tag, "q%d", i); | ||||
if (error) { | if (error) { | ||||
device_printf(dev, "bus_describe_intr() for Queue %d" | device_printf(dev, "bus_describe_intr() for Queue %d" | ||||
" interrupt name failed, error %d\n", | " interrupt name failed, error %d\n", | ||||
que->me, error); | que->me, error); | ||||
} | } | ||||
Show All 17 Lines | |||||
* When used in a virtualized environment PCI BUSMASTER capability may not be set | * When used in a virtualized environment PCI BUSMASTER capability may not be set | ||||
* so explicity set it here and rewrite the ENABLE in the MSIX control register | * so explicity set it here and rewrite the ENABLE in the MSIX control register | ||||
* at this point to cause the host to successfully initialize us. | * at this point to cause the host to successfully initialize us. | ||||
*/ | */ | ||||
void | void | ||||
ixl_set_busmaster(device_t dev) | ixl_set_busmaster(device_t dev) | ||||
{ | { | ||||
u16 pci_cmd_word; | u16 pci_cmd_word; | ||||
int msix_ctrl, rid; | |||||
pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); | pci_cmd_word = pci_read_config(dev, PCIR_COMMAND, 2); | ||||
pci_cmd_word |= PCIM_CMD_BUSMASTEREN; | pci_cmd_word |= PCIM_CMD_BUSMASTEREN; | ||||
pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); | pci_write_config(dev, PCIR_COMMAND, pci_cmd_word, 2); | ||||
} | |||||
/* | |||||
* rewrite the ENABLE in the MSIX control register | |||||
* to cause the host to successfully initialize us. | |||||
*/ | |||||
void | |||||
ixl_set_msix_enable(device_t dev) | |||||
{ | |||||
int msix_ctrl, rid; | |||||
pci_find_cap(dev, PCIY_MSIX, &rid); | pci_find_cap(dev, PCIY_MSIX, &rid); | ||||
rid += PCIR_MSIX_CTRL; | rid += PCIR_MSIX_CTRL; | ||||
msix_ctrl = pci_read_config(dev, rid, 2); | msix_ctrl = pci_read_config(dev, rid, 2); | ||||
msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; | msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; | ||||
pci_write_config(dev, rid, msix_ctrl, 2); | pci_write_config(dev, rid, msix_ctrl, 2); | ||||
} | } | ||||
/* | /* | ||||
* Allocate MSI/X vectors from the OS. | * Allocate MSI/X vectors from the OS. | ||||
* Returns 0 for legacy, 1 for MSI, >1 for MSIX. | * Returns 0 for legacy, 1 for MSI, >1 for MSIX. | ||||
*/ | */ | ||||
int | int | ||||
ixl_init_msix(struct ixl_pf *pf) | ixl_init_msix(struct ixl_pf *pf) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
int auto_max_queues; | int auto_max_queues; | ||||
int rid, want, vectors, queues, available; | int rid, want, vectors, queues, available; | ||||
#ifdef IXL_IW | |||||
int iw_want, iw_vectors; | |||||
pf->iw_msix = 0; | |||||
#endif | |||||
/* Override by tuneable */ | /* Override by tuneable */ | ||||
if (!pf->enable_msix) | if (!pf->enable_msix) | ||||
goto no_msix; | goto no_msix; | ||||
/* Ensure proper operation in virtualized environment */ | /* Ensure proper operation in virtualized environment */ | ||||
ixl_set_busmaster(dev); | ixl_set_busmaster(dev); | ||||
/* First try MSI/X */ | /* First try MSI/X */ | ||||
rid = PCIR_BAR(IXL_BAR); | rid = PCIR_BAR(IXL_MSIX_BAR); | ||||
pf->msix_mem = bus_alloc_resource_any(dev, | pf->msix_mem = bus_alloc_resource_any(dev, | ||||
SYS_RES_MEMORY, &rid, RF_ACTIVE); | SYS_RES_MEMORY, &rid, RF_ACTIVE); | ||||
if (!pf->msix_mem) { | if (!pf->msix_mem) { | ||||
/* May not be enabled */ | /* May not be enabled */ | ||||
device_printf(pf->dev, | device_printf(pf->dev, | ||||
"Unable to map MSIX table\n"); | "Unable to map MSIX table\n"); | ||||
goto no_msix; | goto no_msix; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | #endif | ||||
want = queues + 1; | want = queues + 1; | ||||
if (want <= available) /* Have enough */ | if (want <= available) /* Have enough */ | ||||
vectors = want; | vectors = want; | ||||
else { | else { | ||||
device_printf(pf->dev, | device_printf(pf->dev, | ||||
"MSIX Configuration Problem, " | "MSIX Configuration Problem, " | ||||
"%d vectors available but %d wanted!\n", | "%d vectors available but %d wanted!\n", | ||||
available, want); | available, want); | ||||
return (0); /* Will go to Legacy setup */ | pf->msix_mem = NULL; | ||||
goto no_msix; /* Will go to Legacy setup */ | |||||
} | } | ||||
#ifdef IXL_IW | |||||
if (ixl_enable_iwarp) { | |||||
/* iWARP wants additional vector for CQP */ | |||||
iw_want = mp_ncpus + 1; | |||||
available -= vectors; | |||||
if (available > 0) { | |||||
iw_vectors = (available >= iw_want) ? | |||||
iw_want : available; | |||||
vectors += iw_vectors; | |||||
} else | |||||
iw_vectors = 0; | |||||
} | |||||
#endif | |||||
ixl_set_msix_enable(dev); | |||||
if (pci_alloc_msix(dev, &vectors) == 0) { | if (pci_alloc_msix(dev, &vectors) == 0) { | ||||
device_printf(pf->dev, | device_printf(pf->dev, | ||||
"Using MSIX interrupts with %d vectors\n", vectors); | "Using MSIX interrupts with %d vectors\n", vectors); | ||||
pf->msix = vectors; | pf->msix = vectors; | ||||
#ifdef IXL_IW | |||||
if (ixl_enable_iwarp) | |||||
pf->iw_msix = iw_vectors; | |||||
#endif | |||||
pf->vsi.num_queues = queues; | pf->vsi.num_queues = queues; | ||||
#ifdef RSS | #ifdef RSS | ||||
/* | /* | ||||
* If we're doing RSS, the number of queues needs to | * If we're doing RSS, the number of queues needs to | ||||
* match the number of RSS buckets that are configured. | * match the number of RSS buckets that are configured. | ||||
* | * | ||||
* + If there's more queues than RSS buckets, we'll end | * + If there's more queues than RSS buckets, we'll end | ||||
* up with queues that get no traffic. | * up with queues that get no traffic. | ||||
Show All 10 Lines | #ifdef RSS | ||||
} | } | ||||
#endif | #endif | ||||
return (vectors); | return (vectors); | ||||
} | } | ||||
no_msix: | no_msix: | ||||
vectors = pci_msi_count(dev); | vectors = pci_msi_count(dev); | ||||
pf->vsi.num_queues = 1; | pf->vsi.num_queues = 1; | ||||
pf->max_queues = 1; | pf->max_queues = 1; | ||||
pf->enable_msix = 0; | |||||
if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) | if (vectors == 1 && pci_alloc_msi(dev, &vectors) == 0) | ||||
device_printf(pf->dev, "Using an MSI interrupt\n"); | device_printf(pf->dev, "Using an MSI interrupt\n"); | ||||
else { | else { | ||||
vectors = 0; | vectors = 0; | ||||
device_printf(pf->dev, "Using a Legacy interrupt\n"); | device_printf(pf->dev, "Using a Legacy interrupt\n"); | ||||
} | } | ||||
return (vectors); | return (vectors); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Configure for MSI single vector operation | * Configure for MSI single vector operation | ||||
*/ | */ | ||||
void | void | ||||
ixl_configure_legacy(struct ixl_pf *pf) | ixl_configure_legacy(struct ixl_pf *pf) | ||||
{ | { | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
struct ixl_vsi *vsi = &pf->vsi; | |||||
struct ixl_queue *que = vsi->queues; | |||||
struct rx_ring *rxr = &que->rxr; | |||||
struct tx_ring *txr = &que->txr; | |||||
u32 reg; | u32 reg; | ||||
wr32(hw, I40E_PFINT_ITR0(0), 0); | /* Configure ITR */ | ||||
wr32(hw, I40E_PFINT_ITR0(1), 0); | vsi->tx_itr_setting = pf->tx_itr; | ||||
wr32(hw, I40E_PFINT_ITR0(IXL_TX_ITR), | |||||
vsi->tx_itr_setting); | |||||
txr->itr = vsi->tx_itr_setting; | |||||
vsi->rx_itr_setting = pf->rx_itr; | |||||
wr32(hw, I40E_PFINT_ITR0(IXL_RX_ITR), | |||||
vsi->rx_itr_setting); | |||||
rxr->itr = vsi->rx_itr_setting; | |||||
/* Setup "other" causes */ | /* Setup "other" causes */ | ||||
reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | reg = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | ||||
| I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | | I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK | ||||
| I40E_PFINT_ICR0_ENA_GRST_MASK | | I40E_PFINT_ICR0_ENA_GRST_MASK | ||||
| I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK | | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK | ||||
| I40E_PFINT_ICR0_ENA_GPIO_MASK | | I40E_PFINT_ICR0_ENA_GPIO_MASK | ||||
| I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK | | I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK | ||||
| I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | ||||
| I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK | | I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK | ||||
| I40E_PFINT_ICR0_ENA_VFLR_MASK | | I40E_PFINT_ICR0_ENA_VFLR_MASK | ||||
| I40E_PFINT_ICR0_ENA_ADMINQ_MASK | | I40E_PFINT_ICR0_ENA_ADMINQ_MASK | ||||
; | ; | ||||
wr32(hw, I40E_PFINT_ICR0_ENA, reg); | wr32(hw, I40E_PFINT_ICR0_ENA, reg); | ||||
/* SW_ITR_IDX = 0, but don't change INTENA */ | /* No ITR for non-queue interrupts */ | ||||
wr32(hw, I40E_PFINT_DYN_CTL0, | wr32(hw, I40E_PFINT_STAT_CTL0, | ||||
I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK | | IXL_ITR_NONE << I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT); | ||||
I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK); | |||||
/* SW_ITR_IDX = 0, OTHER_ITR_IDX = 0 */ | |||||
wr32(hw, I40E_PFINT_STAT_CTL0, 0); | |||||
/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ | /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */ | ||||
wr32(hw, I40E_PFINT_LNKLST0, 0); | wr32(hw, I40E_PFINT_LNKLST0, 0); | ||||
/* Associate the queue pair to the vector and enable the q int */ | /* Associate the queue pair to the vector and enable the q int */ | ||||
reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | reg = I40E_QINT_RQCTL_CAUSE_ENA_MASK | ||||
| (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | | (IXL_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | ||||
| (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); | | (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Teardown and release the admin queue/misc vector | * Teardown and release the admin queue/misc vector | ||||
* interrupt. | * interrupt. | ||||
*/ | */ | ||||
int | int | ||||
ixl_teardown_adminq_msix(struct ixl_pf *pf) | ixl_teardown_adminq_msix(struct ixl_pf *pf) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
int rid; | int rid, error = 0; | ||||
if (pf->admvec) /* we are doing MSIX */ | if (pf->admvec) /* we are doing MSIX */ | ||||
rid = pf->admvec + 1; | rid = pf->admvec + 1; | ||||
else | else | ||||
(pf->msix != 0) ? (rid = 1):(rid = 0); | (pf->msix != 0) ? (rid = 1):(rid = 0); | ||||
if (pf->tag != NULL) { | if (pf->tag != NULL) { | ||||
bus_teardown_intr(dev, pf->res, pf->tag); | bus_teardown_intr(dev, pf->res, pf->tag); | ||||
if (error) { | |||||
device_printf(dev, "bus_teardown_intr() for" | |||||
" interrupt 0 failed\n"); | |||||
// return (ENXIO); | |||||
} | |||||
pf->tag = NULL; | pf->tag = NULL; | ||||
} | } | ||||
if (pf->res != NULL) { | if (pf->res != NULL) { | ||||
bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); | bus_release_resource(dev, SYS_RES_IRQ, rid, pf->res); | ||||
if (error) { | |||||
device_printf(dev, "bus_release_resource() for" | |||||
" interrupt 0 failed [rid=%d]\n", rid); | |||||
// return (ENXIO); | |||||
} | |||||
pf->res = NULL; | pf->res = NULL; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
ixl_teardown_queue_msix(struct ixl_vsi *vsi) | ixl_teardown_queue_msix(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; | ||||
device_t dev = vsi->dev; | device_t dev = vsi->dev; | ||||
int rid, error = 0; | int rid, error = 0; | ||||
/* We may get here before stations are setup */ | /* We may get here before stations are setup */ | ||||
if ((!pf->enable_msix) || (que == NULL)) | if ((pf->msix < 2) || (que == NULL)) | ||||
return (0); | return (0); | ||||
/* Release all MSIX queue resources */ | /* Release all MSIX queue resources */ | ||||
for (int i = 0; i < vsi->num_queues; i++, que++) { | for (int i = 0; i < vsi->num_queues; i++, que++) { | ||||
rid = que->msix + 1; | rid = que->msix + 1; | ||||
if (que->tag != NULL) { | if (que->tag != NULL) { | ||||
error = bus_teardown_intr(dev, que->res, que->tag); | error = bus_teardown_intr(dev, que->res, que->tag); | ||||
if (error) { | if (error) { | ||||
Show All 23 Lines | |||||
ixl_free_pci_resources(struct ixl_pf *pf) | ixl_free_pci_resources(struct ixl_pf *pf) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
int memrid; | int memrid; | ||||
ixl_teardown_queue_msix(&pf->vsi); | ixl_teardown_queue_msix(&pf->vsi); | ||||
ixl_teardown_adminq_msix(pf); | ixl_teardown_adminq_msix(pf); | ||||
if (pf->msix) | if (pf->msix > 0) | ||||
pci_release_msi(dev); | pci_release_msi(dev); | ||||
memrid = PCIR_BAR(IXL_BAR); | memrid = PCIR_BAR(IXL_MSIX_BAR); | ||||
if (pf->msix_mem != NULL) | if (pf->msix_mem != NULL) | ||||
bus_release_resource(dev, SYS_RES_MEMORY, | bus_release_resource(dev, SYS_RES_MEMORY, | ||||
memrid, pf->msix_mem); | memrid, pf->msix_mem); | ||||
if (pf->pci_mem != NULL) | if (pf->pci_mem != NULL) | ||||
bus_release_resource(dev, SYS_RES_MEMORY, | bus_release_resource(dev, SYS_RES_MEMORY, | ||||
PCIR_BAR(0), pf->pci_mem); | PCIR_BAR(0), pf->pci_mem); | ||||
return; | return; | ||||
} | } | ||||
void | void | ||||
ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type) | ixl_add_ifmedia(struct ixl_vsi *vsi, u64 phy_types) | ||||
{ | { | ||||
/* Display supported media types */ | /* Display supported media types */ | ||||
if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX)) | if (phy_types & (I40E_CAP_PHY_TYPE_100BASE_TX)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL); | ||||
if (phy_type & (1 << I40E_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_type & (1 << I40E_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_type & (1 << I40E_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_type & (1 << I40E_PHY_TYPE_XAUI) || | if (phy_types & (I40E_CAP_PHY_TYPE_XAUI) || | ||||
phy_type & (1 << I40E_PHY_TYPE_XFI) || | phy_types & (I40E_CAP_PHY_TYPE_XFI) || | ||||
phy_type & (1 << I40E_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_type & (1 << I40E_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_type & (1 << I40E_PHY_TYPE_10GBASE_LR)) | if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_LR)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T)) | if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_T)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4) || | if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_CR4) || | ||||
phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) || | phy_types & (I40E_CAP_PHY_TYPE_40GBASE_CR4_CU) || | ||||
phy_type & (1 << I40E_PHY_TYPE_40GBASE_AOC) || | phy_types & (I40E_CAP_PHY_TYPE_40GBASE_AOC) || | ||||
phy_type & (1 << I40E_PHY_TYPE_XLAUI) || | phy_types & (I40E_CAP_PHY_TYPE_XLAUI) || | ||||
phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) | phy_types & (I40E_CAP_PHY_TYPE_40GBASE_KR4)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4)) | if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_SR4)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4)) | if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_LR4)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_KX)) | if (phy_types & (I40E_CAP_PHY_TYPE_1000BASE_KX)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_KX, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) | if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_CR1_CU) | ||||
|| phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1)) | || phy_types & (I40E_CAP_PHY_TYPE_10GBASE_CR1)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_CR1, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_AOC)) | if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_AOC)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX_LONG, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_SFI)) | if (phy_types & (I40E_CAP_PHY_TYPE_SFI)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SFI, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KX4)) | if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_KX4)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KX4, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_KR)) | if (phy_types & (I40E_CAP_PHY_TYPE_10GBASE_KR)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_KR, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_20GBASE_KR2)) | if (phy_types & (I40E_CAP_PHY_TYPE_20GBASE_KR2)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_20G_KR2, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_KR4)) | if (phy_types & (I40E_CAP_PHY_TYPE_40GBASE_KR4)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_KR4, 0, NULL); | ||||
if (phy_type & (1 << I40E_PHY_TYPE_XLPPI)) | if (phy_types & (I40E_CAP_PHY_TYPE_XLPPI)) | ||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL); | ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_XLPPI, 0, NULL); | ||||
if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_KR)) | |||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_25G_KR, 0, NULL); | |||||
if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_CR)) | |||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_25G_CR, 0, NULL); | |||||
if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_SR)) | |||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_25G_SR, 0, NULL); | |||||
if (phy_types & (I40E_CAP_PHY_TYPE_25GBASE_LR)) | |||||
ifmedia_add(&vsi->media, IFM_ETHER | IFM_UNKNOWN, 0, NULL); | |||||
} | } | ||||
/********************************************************************* | /********************************************************************* | ||||
* | * | ||||
* Setup networking device structure and register an interface. | * Setup networking device structure and register an interface. | ||||
* | * | ||||
**********************************************************************/ | **********************************************************************/ | ||||
int | int | ||||
ixl_setup_interface(device_t dev, struct ixl_vsi *vsi) | ixl_setup_interface(device_t dev, struct ixl_vsi *vsi) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)vsi->back; | |||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct i40e_hw *hw = vsi->hw; | struct i40e_hw *hw = vsi->hw; | ||||
struct ixl_queue *que = vsi->queues; | struct ixl_queue *que = vsi->queues; | ||||
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 (-1); | ||||
} | } | ||||
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_baudrate = IF_Gbps(40); | |||||
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; | ||||
#if __FreeBSD_version >= 1100036 | #if __FreeBSD_version >= 1100036 | ||||
if_setgetcounterfn(ifp, ixl_get_counter); | if_setgetcounterfn(ifp, ixl_get_counter); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | 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); | ||||
return (0); | return (0); | ||||
} | } | ||||
pf->supported_speeds = abilities.link_speed; | |||||
ifp->if_baudrate = ixl_max_aq_speed_to_value(pf->supported_speeds); | |||||
ixl_add_ifmedia(vsi, abilities.phy_type); | 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 53 Lines • ▼ Show 20 Lines | if (ret) { | ||||
return (ret); | return (ret); | ||||
} | } | ||||
if (pf->dbg_mask & IXL_DBG_SWITCH_INFO) { | if (pf->dbg_mask & IXL_DBG_SWITCH_INFO) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"Switch config: header reported: %d in structure, %d total\n", | "Switch config: header reported: %d in structure, %d total\n", | ||||
sw_config->header.num_reported, sw_config->header.num_total); | sw_config->header.num_reported, sw_config->header.num_total); | ||||
for (int i = 0; i < sw_config->header.num_reported; i++) { | for (int i = 0; i < sw_config->header.num_reported; i++) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%d: type=%d seid=%d uplink=%d downlink=%d\n", i, | "-> %d: type=%d seid=%d uplink=%d downlink=%d\n", i, | ||||
sw_config->element[i].element_type, | sw_config->element[i].element_type, | ||||
sw_config->element[i].seid, | sw_config->element[i].seid, | ||||
sw_config->element[i].uplink_seid, | sw_config->element[i].uplink_seid, | ||||
sw_config->element[i].downlink_seid); | sw_config->element[i].downlink_seid); | ||||
} | } | ||||
} | } | ||||
/* Simplified due to a single VSI */ | /* Simplified due to a single VSI */ | ||||
vsi->uplink_seid = sw_config->element[0].uplink_seid; | vsi->uplink_seid = sw_config->element[0].uplink_seid; | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | ixl_initialize_vsi(struct ixl_vsi *vsi) | ||||
/* Set VLAN receive stripping mode */ | /* Set VLAN receive stripping mode */ | ||||
ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; | ctxt.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID; | ||||
ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; | ctxt.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL; | ||||
if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) | if (vsi->ifp->if_capenable & IFCAP_VLAN_HWTAGGING) | ||||
ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; | ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH; | ||||
else | else | ||||
ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; | ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING; | ||||
#ifdef IXL_IW | |||||
/* Set TCP Enable for iWARP capable VSI */ | |||||
if (ixl_enable_iwarp && pf->iw_enabled) { | |||||
ctxt.info.valid_sections |= | |||||
htole16(I40E_AQ_VSI_PROP_QUEUE_OPT_VALID); | |||||
ctxt.info.queueing_opt_flags |= I40E_AQ_VSI_QUE_OPT_TCP_ENA; | |||||
} | |||||
#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_add = 0; | ||||
vsi->hw_filters_del = 0; | vsi->hw_filters_del = 0; | ||||
▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | ixl_setup_queue(struct ixl_queue *que, struct ixl_pf *pf, int index) | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
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 tx_ring *txr = &que->txr; | struct tx_ring *txr = &que->txr; | ||||
struct rx_ring *rxr = &que->rxr; | struct rx_ring *rxr = &que->rxr; | ||||
int error = 0; | int error = 0; | ||||
int rsize, tsize; | int rsize, tsize; | ||||
/* ERJ: A lot of references to external objects... */ | |||||
que->num_desc = pf->ringsz; | que->num_desc = pf->ringsz; | ||||
que->me = index; | que->me = index; | ||||
que->vsi = vsi; | que->vsi = vsi; | ||||
txr->que = que; | txr->que = que; | ||||
txr->tail = I40E_QTX_TAIL(que->me); | txr->tail = I40E_QTX_TAIL(que->me); | ||||
/* Initialize the TX lock */ | /* Initialize the TX lock */ | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | /* Get memory for the station queues */ | ||||
if (!(vsi->queues = | if (!(vsi->queues = | ||||
(struct ixl_queue *) malloc(sizeof(struct ixl_queue) * | (struct ixl_queue *) malloc(sizeof(struct ixl_queue) * | ||||
vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { | vsi->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { | ||||
device_printf(dev, "Unable to allocate queue memory\n"); | device_printf(dev, "Unable to allocate queue memory\n"); | ||||
error = ENOMEM; | error = ENOMEM; | ||||
return (error); | return (error); | ||||
} | } | ||||
/* Then setup each queue */ | |||||
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_setup_queue(que, pf, i); | error = ixl_setup_queue(que, pf, i); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | case IXL_BULK_LATENCY: | ||||
} | } | ||||
rxr->latency = rx_latency; | rxr->latency = rx_latency; | ||||
if (rx_itr != rxr->itr) { | if (rx_itr != rxr->itr) { | ||||
/* do an exponential smoothing */ | /* do an exponential smoothing */ | ||||
rx_itr = (10 * rx_itr * rxr->itr) / | rx_itr = (10 * rx_itr * rxr->itr) / | ||||
((9 * rx_itr) + rxr->itr); | ((9 * rx_itr) + rxr->itr); | ||||
rxr->itr = rx_itr & IXL_MAX_ITR; | rxr->itr = min(rx_itr, IXL_MAX_ITR); | ||||
wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, | wr32(hw, I40E_PFINT_ITRN(IXL_RX_ITR, | ||||
que->me), rxr->itr); | que->me), rxr->itr); | ||||
} | } | ||||
} else { /* We may have have toggled to non-dynamic */ | } else { /* We may have have toggled to non-dynamic */ | ||||
if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) | if (vsi->rx_itr_setting & IXL_ITR_DYNAMIC) | ||||
vsi->rx_itr_setting = pf->rx_itr; | vsi->rx_itr_setting = pf->rx_itr; | ||||
/* Update the hardware if needed */ | /* Update the hardware if needed */ | ||||
if (rxr->itr != vsi->rx_itr_setting) { | if (rxr->itr != vsi->rx_itr_setting) { | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (pf->dynamic_tx_itr) { | ||||
} | } | ||||
txr->latency = tx_latency; | txr->latency = tx_latency; | ||||
if (tx_itr != txr->itr) { | if (tx_itr != txr->itr) { | ||||
/* do an exponential smoothing */ | /* do an exponential smoothing */ | ||||
tx_itr = (10 * tx_itr * txr->itr) / | tx_itr = (10 * tx_itr * txr->itr) / | ||||
((9 * tx_itr) + txr->itr); | ((9 * tx_itr) + txr->itr); | ||||
txr->itr = tx_itr & IXL_MAX_ITR; | txr->itr = min(tx_itr, IXL_MAX_ITR); | ||||
wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, | wr32(hw, I40E_PFINT_ITRN(IXL_TX_ITR, | ||||
que->me), txr->itr); | que->me), txr->itr); | ||||
} | } | ||||
} else { /* We may have have toggled to non-dynamic */ | } else { /* We may have have toggled to non-dynamic */ | ||||
if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) | if (vsi->tx_itr_setting & IXL_ITR_DYNAMIC) | ||||
vsi->tx_itr_setting = pf->tx_itr; | vsi->tx_itr_setting = pf->tx_itr; | ||||
/* Update the hardware if needed */ | /* Update the hardware if needed */ | ||||
Show All 26 Lines | |||||
} | } | ||||
#ifdef IXL_DEBUG | #ifdef IXL_DEBUG | ||||
/** | /** | ||||
* ixl_sysctl_qtx_tail_handler | * ixl_sysctl_qtx_tail_handler | ||||
* Retrieves I40E_QTX_TAIL value from hardware | * Retrieves I40E_QTX_TAIL value from hardware | ||||
* for a sysctl. | * for a sysctl. | ||||
*/ | */ | ||||
int | static int | ||||
ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS) | ixl_sysctl_qtx_tail_handler(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ixl_queue *que; | struct ixl_queue *que; | ||||
int error; | int error; | ||||
u32 val; | u32 val; | ||||
que = ((struct ixl_queue *)oidp->oid_arg1); | que = ((struct ixl_queue *)oidp->oid_arg1); | ||||
if (!que) return 0; | if (!que) return 0; | ||||
val = rd32(que->vsi->hw, que->txr.tail); | val = rd32(que->vsi->hw, que->txr.tail); | ||||
error = sysctl_handle_int(oidp, &val, 0, req); | error = sysctl_handle_int(oidp, &val, 0, req); | ||||
if (error || !req->newptr) | if (error || !req->newptr) | ||||
return error; | return error; | ||||
return (0); | return (0); | ||||
} | } | ||||
/** | /** | ||||
* ixl_sysctl_qrx_tail_handler | * ixl_sysctl_qrx_tail_handler | ||||
* Retrieves I40E_QRX_TAIL value from hardware | * Retrieves I40E_QRX_TAIL value from hardware | ||||
* for a sysctl. | * for a sysctl. | ||||
*/ | */ | ||||
int | static int | ||||
ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS) | ixl_sysctl_qrx_tail_handler(SYSCTL_HANDLER_ARGS) | ||||
{ | { | ||||
struct ixl_queue *que; | struct ixl_queue *que; | ||||
int error; | int error; | ||||
u32 val; | u32 val; | ||||
que = ((struct ixl_queue *)oidp->oid_arg1); | que = ((struct ixl_queue *)oidp->oid_arg1); | ||||
if (!que) return 0; | if (!que) return 0; | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "irqs", | ||||
CTLFLAG_RD, &(queues[q].irqs), | CTLFLAG_RD, &(queues[q].irqs), | ||||
"irqs on this queue"); | "irqs on this queue"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tso_tx", | ||||
CTLFLAG_RD, &(queues[q].tso), | CTLFLAG_RD, &(queues[q].tso), | ||||
"TSO"); | "TSO"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dmamap_failed", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_dmamap_failed", | ||||
CTLFLAG_RD, &(queues[q].tx_dmamap_failed), | CTLFLAG_RD, &(queues[q].tx_dmamap_failed), | ||||
"Driver tx dma failure in xmit"); | "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", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "no_desc_avail", | ||||
CTLFLAG_RD, &(txr->no_desc), | CTLFLAG_RD, &(txr->no_desc), | ||||
"Queue No Descriptor Available"); | "Queue No Descriptor Available"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_packets", | ||||
CTLFLAG_RD, &(txr->total_packets), | CTLFLAG_RD, &(txr->total_packets), | ||||
"Queue Packets Transmitted"); | "Queue Packets Transmitted"); | ||||
SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", | SYSCTL_ADD_UQUAD(ctx, queue_list, OID_AUTO, "tx_bytes", | ||||
CTLFLAG_RD, &(txr->tx_bytes), | CTLFLAG_RD, &(txr->tx_bytes), | ||||
▲ Show 20 Lines • Show All 192 Lines • ▼ Show 20 Lines | if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6) | ||||
set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); | set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) | if (rss_hash_config & RSS_HASHTYPE_RSS_IPV6_EX) | ||||
set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); | set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) | if (rss_hash_config & RSS_HASHTYPE_RSS_TCP_IPV6) | ||||
set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); | set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); | ||||
if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) | if (rss_hash_config & RSS_HASHTYPE_RSS_UDP_IPV6) | ||||
set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); | set_hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP); | ||||
#else | #else | ||||
set_hena = IXL_DEFAULT_RSS_HENA; | if (hw->mac.type == I40E_MAC_X722) | ||||
set_hena = IXL_DEFAULT_RSS_HENA_X722; | |||||
else | |||||
set_hena = IXL_DEFAULT_RSS_HENA_XL710; | |||||
#endif | #endif | ||||
hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) | | hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) | | ||||
((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32); | ((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32); | ||||
hena |= set_hena; | hena |= set_hena; | ||||
i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena); | i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (u32)hena); | ||||
i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); | i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32)); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 675 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
ixl_enable_intr(struct ixl_vsi *vsi) | ixl_enable_intr(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 = vsi->hw; | struct i40e_hw *hw = vsi->hw; | ||||
struct ixl_queue *que = vsi->queues; | struct ixl_queue *que = vsi->queues; | ||||
if (pf->enable_msix) { | if (pf->msix > 1) { | ||||
for (int i = 0; i < vsi->num_queues; i++, que++) | for (int i = 0; i < vsi->num_queues; i++, que++) | ||||
ixl_enable_queue(hw, que->me); | ixl_enable_queue(hw, que->me); | ||||
} else | } else | ||||
ixl_enable_legacy(hw); | ixl_enable_intr0(hw); | ||||
} | } | ||||
void | void | ||||
ixl_disable_rings_intr(struct ixl_vsi *vsi) | ixl_disable_rings_intr(struct ixl_vsi *vsi) | ||||
{ | { | ||||
struct i40e_hw *hw = vsi->hw; | struct i40e_hw *hw = vsi->hw; | ||||
struct ixl_queue *que = vsi->queues; | struct ixl_queue *que = vsi->queues; | ||||
for (int i = 0; i < vsi->num_queues; i++, que++) | for (int i = 0; i < vsi->num_queues; i++, que++) | ||||
ixl_disable_queue(hw, que->me); | ixl_disable_queue(hw, que->me); | ||||
} | } | ||||
void | void | ||||
ixl_disable_intr(struct ixl_vsi *vsi) | ixl_enable_intr0(struct i40e_hw *hw) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)vsi->back; | |||||
struct i40e_hw *hw = vsi->hw; | |||||
if (pf->enable_msix) | |||||
ixl_disable_adminq(hw); | |||||
else | |||||
ixl_disable_legacy(hw); | |||||
} | |||||
void | |||||
ixl_enable_adminq(struct i40e_hw *hw) | |||||
{ | |||||
u32 reg; | u32 reg; | ||||
/* Use IXL_ITR_NONE so ITR isn't updated here */ | |||||
reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | | reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | | ||||
I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | | ||||
(IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); | (IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); | ||||
wr32(hw, I40E_PFINT_DYN_CTL0, reg); | wr32(hw, I40E_PFINT_DYN_CTL0, reg); | ||||
ixl_flush(hw); | |||||
} | } | ||||
void | void | ||||
ixl_disable_adminq(struct i40e_hw *hw) | ixl_disable_intr0(struct i40e_hw *hw) | ||||
{ | { | ||||
u32 reg; | u32 reg; | ||||
reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; | reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; | ||||
wr32(hw, I40E_PFINT_DYN_CTL0, reg); | wr32(hw, I40E_PFINT_DYN_CTL0, reg); | ||||
ixl_flush(hw); | ixl_flush(hw); | ||||
} | } | ||||
Show All 13 Lines | |||||
{ | { | ||||
u32 reg; | u32 reg; | ||||
reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; | reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT; | ||||
wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); | wr32(hw, I40E_PFINT_DYN_CTLN(id), reg); | ||||
} | } | ||||
void | void | ||||
ixl_enable_legacy(struct i40e_hw *hw) | |||||
{ | |||||
u32 reg; | |||||
reg = I40E_PFINT_DYN_CTL0_INTENA_MASK | | |||||
I40E_PFINT_DYN_CTL0_CLEARPBA_MASK | | |||||
(IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT); | |||||
wr32(hw, I40E_PFINT_DYN_CTL0, reg); | |||||
} | |||||
void | |||||
ixl_disable_legacy(struct i40e_hw *hw) | |||||
{ | |||||
u32 reg; | |||||
reg = IXL_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT; | |||||
wr32(hw, I40E_PFINT_DYN_CTL0, reg); | |||||
} | |||||
void | |||||
ixl_update_stats_counters(struct ixl_pf *pf) | ixl_update_stats_counters(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_vf *vf; | struct ixl_vf *vf; | ||||
struct i40e_hw_port_stats *nsd = &pf->stats; | struct i40e_hw_port_stats *nsd = &pf->stats; | ||||
struct i40e_hw_port_stats *osd = &pf->stats_offsets; | struct i40e_hw_port_stats *osd = &pf->stats_offsets; | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | ixl_rebuild_hw_structs_after_reset(struct ixl_pf *pf) | ||||
/* Teardown */ | /* Teardown */ | ||||
if (is_up) | if (is_up) | ||||
ixl_stop(pf); | ixl_stop(pf); | ||||
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); | ||||
ixl_disable_adminq(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); | ||||
/* 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); | ||||
} | } | ||||
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); | ||||
} | } | ||||
ixl_configure_intr0_msix(pf); | ixl_configure_intr0_msix(pf); | ||||
ixl_enable_adminq(hw); | ixl_enable_intr0(hw); | ||||
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); | ||||
} | } | ||||
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); | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | ixl_do_adminq(void *context, int pending) | ||||
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, &result); | ||||
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, | ||||
"%s: Admin Queue event: %#06x\n", __func__, 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 | ||||
Show All 9 Lines | #endif | ||||
/* | /* | ||||
* If there are still messages to process, reschedule ourselves. | * If there are still messages to process, reschedule ourselves. | ||||
* Otherwise, re-enable our interrupt. | * Otherwise, re-enable our interrupt. | ||||
*/ | */ | ||||
if (result > 0) | if (result > 0) | ||||
taskqueue_enqueue(pf->tq, &pf->adminq); | taskqueue_enqueue(pf->tq, &pf->adminq); | ||||
else | else | ||||
ixl_enable_adminq(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 | ||||
▲ Show 20 Lines • Show All 170 Lines • ▼ Show 20 Lines | ixl_stat_update32(struct i40e_hw *hw, u32 reg, | ||||
else | else | ||||
*stat = (u32)((new_data + ((u64)1 << 32)) - *offset); | *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); | ||||
} | } | ||||
void | void | ||||
ixl_add_device_sysctls(struct ixl_pf *pf) | ixl_add_device_sysctls(struct ixl_pf *pf) | ||||
{ | { | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct i40e_hw *hw = &pf->hw; | |||||
struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); | struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); | ||||
struct sysctl_oid_list *ctx_list = | 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_list *fec_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_set_flowcntl, "I", IXL_SYSCTL_HELP_FC); | pf, 0, ixl_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_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE); | pf, 0, ixl_set_advertise, "I", IXL_SYSCTL_HELP_SET_ADVERTISE); | ||||
Show All 24 Lines | ixl_add_device_sysctls(struct ixl_pf *pf) | ||||
SYSCTL_ADD_INT(ctx, ctx_list, | SYSCTL_ADD_INT(ctx, ctx_list, | ||||
OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW, | OID_AUTO, "dynamic_rx_itr", CTLFLAG_RW, | ||||
&pf->dynamic_rx_itr, 0, "Enable dynamic RX ITR"); | &pf->dynamic_rx_itr, 0, "Enable dynamic RX ITR"); | ||||
SYSCTL_ADD_INT(ctx, ctx_list, | SYSCTL_ADD_INT(ctx, ctx_list, | ||||
OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, | OID_AUTO, "dynamic_tx_itr", CTLFLAG_RW, | ||||
&pf->dynamic_tx_itr, 0, "Enable dynamic TX ITR"); | &pf->dynamic_tx_itr, 0, "Enable dynamic TX ITR"); | ||||
/* Add FEC sysctls for 25G adapters */ | |||||
/* | |||||
* XXX: These settings can be changed, but that isn't supported, | |||||
* so these are read-only for now. | |||||
*/ | |||||
if (hw->device_id == I40E_DEV_ID_25G_B | |||||
|| hw->device_id == I40E_DEV_ID_25G_SFP28) { | |||||
fec_node = SYSCTL_ADD_NODE(ctx, ctx_list, | |||||
OID_AUTO, "fec", CTLFLAG_RD, NULL, "FEC Sysctls"); | |||||
fec_list = SYSCTL_CHILDREN(fec_node); | |||||
SYSCTL_ADD_PROC(ctx, fec_list, | |||||
OID_AUTO, "fc_ability", CTLTYPE_INT | CTLFLAG_RD, | |||||
pf, 0, ixl_sysctl_fec_fc_ability, "I", "FC FEC ability enabled"); | |||||
SYSCTL_ADD_PROC(ctx, fec_list, | |||||
OID_AUTO, "rs_ability", CTLTYPE_INT | CTLFLAG_RD, | |||||
pf, 0, ixl_sysctl_fec_rs_ability, "I", "RS FEC ability enabled"); | |||||
SYSCTL_ADD_PROC(ctx, fec_list, | |||||
OID_AUTO, "fc_requested", CTLTYPE_INT | CTLFLAG_RD, | |||||
pf, 0, ixl_sysctl_fec_fc_request, "I", "FC FEC mode requested on link"); | |||||
SYSCTL_ADD_PROC(ctx, fec_list, | |||||
OID_AUTO, "rs_requested", CTLTYPE_INT | CTLFLAG_RD, | |||||
pf, 0, ixl_sysctl_fec_rs_request, "I", "RS FEC mode requested on link"); | |||||
SYSCTL_ADD_PROC(ctx, fec_list, | |||||
OID_AUTO, "auto_fec_enabled", CTLTYPE_INT | CTLFLAG_RD, | |||||
pf, 0, ixl_sysctl_fec_auto_enable, "I", "Let FW decide FEC ability/request modes"); | |||||
} | |||||
/* 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 All 25 Lines | ixl_add_device_sysctls(struct ixl_pf *pf) | ||||
SYSCTL_ADD_PROC(ctx, debug_list, | SYSCTL_ADD_PROC(ctx, debug_list, | ||||
OID_AUTO, "rss_key", CTLTYPE_STRING | CTLFLAG_RD, | OID_AUTO, "rss_key", CTLTYPE_STRING | CTLFLAG_RD, | ||||
pf, 0, ixl_sysctl_hkey, "A", "View RSS key"); | pf, 0, ixl_sysctl_hkey, "A", "View RSS key"); | ||||
SYSCTL_ADD_PROC(ctx, debug_list, | SYSCTL_ADD_PROC(ctx, debug_list, | ||||
OID_AUTO, "rss_lut", CTLTYPE_STRING | CTLFLAG_RD, | OID_AUTO, "rss_lut", CTLTYPE_STRING | CTLFLAG_RD, | ||||
pf, 0, ixl_sysctl_hlut, "A", "View RSS lookup table"); | pf, 0, ixl_sysctl_hlut, "A", "View RSS lookup table"); | ||||
SYSCTL_ADD_PROC(ctx, debug_list, | |||||
OID_AUTO, "rss_hena", CTLTYPE_ULONG | CTLFLAG_RD, | |||||
pf, 0, ixl_sysctl_hena, "LU", "View enabled packet types for RSS"); | |||||
SYSCTL_ADD_PROC(ctx, debug_list, | |||||
OID_AUTO, "disable_fw_link_management", CTLTYPE_INT | CTLFLAG_WR, | |||||
pf, 0, ixl_sysctl_fw_link_management, "I", "Disable FW Link Management"); | |||||
if (pf->has_i2c) { | |||||
SYSCTL_ADD_PROC(ctx, debug_list, | |||||
OID_AUTO, "read_i2c_byte", CTLTYPE_INT | CTLFLAG_RW, | |||||
pf, 0, ixl_sysctl_read_i2c_byte, "I", "Read byte from I2C bus"); | |||||
SYSCTL_ADD_PROC(ctx, debug_list, | |||||
OID_AUTO, "write_i2c_byte", CTLTYPE_INT | CTLFLAG_RW, | |||||
pf, 0, ixl_sysctl_write_i2c_byte, "I", "Write byte to I2C bus"); | |||||
} | |||||
#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 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | ixl_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); | ||||
} | } | ||||
int | char * | ||||
ixl_current_speed(SYSCTL_HANDLER_ARGS) | ixl_aq_speed_to_str(enum i40e_aq_link_speed link_speed) | ||||
{ | { | ||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | int index; | ||||
struct i40e_hw *hw = &pf->hw; | |||||
int error = 0, index = 0; | |||||
char *speeds[] = { | char *speeds[] = { | ||||
"Unknown", | "Unknown", | ||||
"100M", | "100 Mbps", | ||||
"1G", | "1 Gbps", | ||||
"10G", | "10 Gbps", | ||||
"40G", | "40 Gbps", | ||||
"20G" | "20 Gbps", | ||||
"25 Gbps", | |||||
}; | }; | ||||
ixl_update_link_status(pf); | switch (link_speed) { | ||||
switch (hw->phy.link_info.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: | |||||
index = 6; | |||||
break; | |||||
case I40E_LINK_SPEED_UNKNOWN: | case I40E_LINK_SPEED_UNKNOWN: | ||||
default: | default: | ||||
index = 0; | index = 0; | ||||
break; | break; | ||||
} | } | ||||
error = sysctl_handle_string(oidp, speeds[index], | return speeds[index]; | ||||
strlen(speeds[index]), req); | } | ||||
int | |||||
ixl_current_speed(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
struct i40e_hw *hw = &pf->hw; | |||||
int error = 0; | |||||
ixl_update_link_status(pf); | |||||
error = sysctl_handle_string(oidp, | |||||
ixl_aq_speed_to_str(hw->phy.link_info.link_speed), | |||||
8, req); | |||||
return (error); | return (error); | ||||
} | } | ||||
static u8 | |||||
ixl_convert_sysctl_aq_link_speed(u8 speeds, bool to_aq) | |||||
{ | |||||
static u16 speedmap[6] = { | |||||
(I40E_LINK_SPEED_100MB | (0x1 << 8)), | |||||
(I40E_LINK_SPEED_1GB | (0x2 << 8)), | |||||
(I40E_LINK_SPEED_10GB | (0x4 << 8)), | |||||
(I40E_LINK_SPEED_20GB | (0x8 << 8)), | |||||
(I40E_LINK_SPEED_25GB | (0x10 << 8)), | |||||
(I40E_LINK_SPEED_40GB | (0x20 << 8)) | |||||
}; | |||||
u8 retval = 0; | |||||
for (int i = 0; i < 6; i++) { | |||||
if (to_aq) | |||||
retval |= (speeds & (speedmap[i] >> 8)) ? (speedmap[i] & 0xff) : 0; | |||||
else | |||||
retval |= (speeds & speedmap[i]) ? (speedmap[i] >> 8) : 0; | |||||
} | |||||
return (retval); | |||||
} | |||||
int | int | ||||
ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds) | ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds) | ||||
{ | { | ||||
struct i40e_hw *hw = &pf->hw; | struct i40e_hw *hw = &pf->hw; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct i40e_aq_get_phy_abilities_resp abilities; | struct i40e_aq_get_phy_abilities_resp abilities; | ||||
struct i40e_aq_set_phy_config config; | struct i40e_aq_set_phy_config config; | ||||
enum i40e_status_code aq_error = 0; | enum i40e_status_code aq_error = 0; | ||||
/* Get current capability information */ | /* Get current capability information */ | ||||
aq_error = i40e_aq_get_phy_capabilities(hw, | aq_error = i40e_aq_get_phy_capabilities(hw, | ||||
FALSE, FALSE, &abilities, NULL); | FALSE, FALSE, &abilities, NULL); | ||||
if (aq_error) { | if (aq_error) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: Error getting phy capabilities %d," | "%s: Error getting phy capabilities %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); | ||||
} | } | ||||
/* Prepare new config */ | /* Prepare new config */ | ||||
bzero(&config, sizeof(config)); | bzero(&config, sizeof(config)); | ||||
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.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; | ||||
/* Translate into aq cmd link_speed */ | |||||
if (speeds & 0x10) | |||||
config.link_speed |= I40E_LINK_SPEED_40GB; | |||||
if (speeds & 0x8) | |||||
config.link_speed |= I40E_LINK_SPEED_20GB; | |||||
if (speeds & 0x4) | |||||
config.link_speed |= I40E_LINK_SPEED_10GB; | |||||
if (speeds & 0x2) | |||||
config.link_speed |= I40E_LINK_SPEED_1GB; | |||||
if (speeds & 0x1) | |||||
config.link_speed |= I40E_LINK_SPEED_100MB; | |||||
/* 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 (EAGAIN); | return (EIO); | ||||
} | } | ||||
/* | |||||
** This seems a bit heavy handed, but we | |||||
** need to get a reinit on some devices | |||||
*/ | |||||
IXL_PF_LOCK(pf); | |||||
ixl_stop_locked(pf); | |||||
ixl_init_locked(pf); | |||||
IXL_PF_UNLOCK(pf); | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
** 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 40G | ** 0x10 - advertise 25G | ||||
** 0x20 - advertise 40G | |||||
** | ** | ||||
** Set to 0 to disable link | ** Set to 0 to disable link | ||||
*/ | */ | ||||
int | int | ||||
ixl_set_advertise(SYSCTL_HANDLER_ARGS) | ixl_set_advertise(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; | ||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
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); | ||||
/* Check for sane value */ | /* Check if changing speeds is supported */ | ||||
if (requested_ls > 0x10) { | |||||
device_printf(dev, "Invalid advertised speed; " | |||||
"valid modes are 0x1 through 0x10\n"); | |||||
return (EINVAL); | |||||
} | |||||
/* Then check for validity based on adapter type */ | |||||
switch (hw->device_id) { | switch (hw->device_id) { | ||||
case I40E_DEV_ID_1G_BASE_T_X722: | case I40E_DEV_ID_25G_B: | ||||
/* 1G BaseT */ | case I40E_DEV_ID_25G_SFP28: | ||||
if (requested_ls & ~(0x2)) { | device_printf(dev, "Changing advertised speeds not supported" | ||||
device_printf(dev, | " on this device.\n"); | ||||
"Only 1G speeds supported on this device.\n"); | |||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
break; | if (requested_ls < 0 || requested_ls > 0xff) { | ||||
case I40E_DEV_ID_10G_BASE_T: | |||||
case I40E_DEV_ID_10G_BASE_T4: | |||||
/* 10G BaseT */ | |||||
if (requested_ls & ~(0x7)) { | |||||
device_printf(dev, | |||||
"Only 100M/1G/10G speeds supported on this device.\n"); | |||||
return (EINVAL); | |||||
} | } | ||||
break; | |||||
case I40E_DEV_ID_20G_KR2: | /* Check for valid value */ | ||||
case I40E_DEV_ID_20G_KR2_A: | converted_speeds = ixl_convert_sysctl_aq_link_speed((u8)requested_ls, true); | ||||
/* 20G */ | if ((converted_speeds | pf->supported_speeds) != pf->supported_speeds) { | ||||
if (requested_ls & ~(0xE)) { | device_printf(dev, "Invalid advertised speed; " | ||||
device_printf(dev, | "valid flags are: 0x%02x\n", | ||||
"Only 1G/10G/20G speeds supported on this device.\n"); | ixl_convert_sysctl_aq_link_speed(pf->supported_speeds, false)); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
break; | |||||
case I40E_DEV_ID_KX_B: | |||||
case I40E_DEV_ID_QSFP_A: | |||||
case I40E_DEV_ID_QSFP_B: | |||||
/* 40G */ | |||||
if (requested_ls & ~(0x10)) { | |||||
device_printf(dev, | |||||
"Only 40G speeds supported on this device.\n"); | |||||
return (EINVAL); | |||||
} | |||||
break; | |||||
default: | |||||
/* 10G (1G) */ | |||||
if (requested_ls & ~(0x6)) { | |||||
device_printf(dev, | |||||
"Only 1/10G speeds supported on this device.\n"); | |||||
return (EINVAL); | |||||
} | |||||
break; | |||||
} | |||||
/* Exit if no change */ | |||||
if (pf->advertised_speed == requested_ls) | |||||
return (0); | |||||
error = ixl_set_advertised_speeds(pf, requested_ls); | error = ixl_set_advertised_speeds(pf, requested_ls); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
pf->advertised_speed = requested_ls; | pf->advertised_speed = requested_ls; | ||||
ixl_update_link_status(pf); | ixl_update_link_status(pf); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Input: bitmap of enum i40e_aq_link_speed | |||||
*/ | |||||
static u64 | |||||
ixl_max_aq_speed_to_value(u8 link_speeds) | |||||
{ | |||||
if (link_speeds & I40E_LINK_SPEED_40GB) | |||||
return IF_Gbps(40); | |||||
if (link_speeds & I40E_LINK_SPEED_25GB) | |||||
return IF_Gbps(25); | |||||
if (link_speeds & I40E_LINK_SPEED_20GB) | |||||
return IF_Gbps(20); | |||||
if (link_speeds & I40E_LINK_SPEED_10GB) | |||||
return IF_Gbps(10); | |||||
if (link_speeds & I40E_LINK_SPEED_1GB) | |||||
return IF_Gbps(1); | |||||
if (link_speeds & I40E_LINK_SPEED_100MB) | |||||
return IF_Mbps(100); | |||||
else | |||||
/* Minimum supported link speed */ | |||||
return IF_Mbps(100); | |||||
} | |||||
/* | |||||
** Get the width and transaction speed of | ** Get the width and transaction speed of | ||||
** the bus this adapter is plugged into. | ** the bus this adapter is plugged into. | ||||
*/ | */ | ||||
void | void | ||||
ixl_get_bus_info(struct i40e_hw *hw, device_t dev) | ixl_get_bus_info(struct ixl_pf *pf) | ||||
{ | { | ||||
struct i40e_hw *hw = &pf->hw; | |||||
device_t dev = pf->dev; | |||||
u16 link; | u16 link; | ||||
u32 offset; | u32 offset, num_ports; | ||||
u64 max_speed; | |||||
/* Some devices don't use PCIE */ | /* Some devices don't use PCIE */ | ||||
if (hw->mac.type == I40E_MAC_X722) | if (hw->mac.type == I40E_MAC_X722) | ||||
return; | return; | ||||
/* Read PCI Express Capabilities Link Status Register */ | /* Read PCI Express Capabilities Link Status Register */ | ||||
pci_find_cap(dev, PCIY_EXPRESS, &offset); | pci_find_cap(dev, PCIY_EXPRESS, &offset); | ||||
link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); | link = pci_read_config(dev, offset + PCIER_LINK_STA, 2); | ||||
/* Fill out hw struct with PCIE info */ | /* Fill out hw struct with PCIE info */ | ||||
i40e_set_pci_config_data(hw, link); | i40e_set_pci_config_data(hw, link); | ||||
/* Use info to print out bandwidth messages */ | /* Use info to print out bandwidth messages */ | ||||
device_printf(dev,"PCI Express Bus: Speed %s %s\n", | device_printf(dev,"PCI Express Bus: Speed %s %s\n", | ||||
((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": | ((hw->bus.speed == i40e_bus_speed_8000) ? "8.0GT/s": | ||||
(hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": | (hw->bus.speed == i40e_bus_speed_5000) ? "5.0GT/s": | ||||
(hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), | (hw->bus.speed == i40e_bus_speed_2500) ? "2.5GT/s":"Unknown"), | ||||
(hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : | (hw->bus.width == i40e_bus_width_pcie_x8) ? "Width x8" : | ||||
(hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : | (hw->bus.width == i40e_bus_width_pcie_x4) ? "Width x4" : | ||||
(hw->bus.width == i40e_bus_width_pcie_x2) ? "Width x2" : | |||||
(hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : | (hw->bus.width == i40e_bus_width_pcie_x1) ? "Width x1" : | ||||
("Unknown")); | ("Unknown")); | ||||
if ((hw->bus.width <= i40e_bus_width_pcie_x8) && | /* | ||||
(hw->bus.speed < i40e_bus_speed_8000)) { | * If adapter is in slot with maximum supported speed, | ||||
* no warning message needs to be printed out. | |||||
*/ | |||||
if (hw->bus.speed >= i40e_bus_speed_8000 | |||||
&& hw->bus.width >= i40e_bus_width_pcie_x8) | |||||
return; | |||||
num_ports = bitcount32(hw->func_caps.valid_functions); | |||||
max_speed = ixl_max_aq_speed_to_value(pf->supported_speeds) / 1000000; | |||||
if ((num_ports * max_speed) > hw->bus.speed * hw->bus.width) { | |||||
device_printf(dev, "PCI-Express bandwidth available" | device_printf(dev, "PCI-Express bandwidth available" | ||||
" for this device may be insufficient for" | " for this device may be insufficient for" | ||||
" optimal performance.\n"); | " optimal performance.\n"); | ||||
device_printf(dev, "For optimal performance, a x8 " | device_printf(dev, "Please move the device to a different" | ||||
"PCIE Gen3 slot is required.\n"); | " PCI-e link with more lanes and/or higher" | ||||
" transfer rate.\n"); | |||||
} | } | ||||
} | } | ||||
static int | static int | ||||
ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS) | ixl_sysctl_show_fw(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; | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | if (!(pf->state & IXL_PF_STATE_EMPR_RESETTING)) { | ||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno); | status = i40e_nvmupd_command(hw, nvma, nvma->data, &perrno); | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
} else { | } else { | ||||
perrno = -EBUSY; | perrno = -EBUSY; | ||||
} | } | ||||
if (status) | if (status) | ||||
device_printf(dev, "i40e_nvmupd_command status %d, perrno %d\n", | device_printf(dev, "i40e_nvmupd_command status %s, perrno %d\n", | ||||
status, perrno); | i40e_stat_str(hw, status), perrno); | ||||
/* | /* | ||||
* -EPERM is actually ERESTART, which the kernel interprets as it needing | * -EPERM is actually ERESTART, which the kernel interprets as it needing | ||||
* 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 | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | switch (hw->phy.link_info.phy_type) { | ||||
case I40E_PHY_TYPE_10GBASE_T: | case I40E_PHY_TYPE_10GBASE_T: | ||||
ifmr->ifm_active |= IFM_10G_T; | ifmr->ifm_active |= IFM_10G_T; | ||||
break; | break; | ||||
case I40E_PHY_TYPE_XAUI: | case I40E_PHY_TYPE_XAUI: | ||||
case I40E_PHY_TYPE_XFI: | case I40E_PHY_TYPE_XFI: | ||||
case I40E_PHY_TYPE_10GBASE_AOC: | case I40E_PHY_TYPE_10GBASE_AOC: | ||||
ifmr->ifm_active |= IFM_OTHER; | ifmr->ifm_active |= IFM_OTHER; | ||||
break; | break; | ||||
/* 25 G */ | |||||
case I40E_PHY_TYPE_25GBASE_KR: | |||||
ifmr->ifm_active |= IFM_25G_KR; | |||||
break; | |||||
case I40E_PHY_TYPE_25GBASE_CR: | |||||
ifmr->ifm_active |= IFM_25G_CR; | |||||
break; | |||||
case I40E_PHY_TYPE_25GBASE_SR: | |||||
ifmr->ifm_active |= IFM_25G_SR; | |||||
break; | |||||
case I40E_PHY_TYPE_25GBASE_LR: | |||||
ifmr->ifm_active |= IFM_UNKNOWN; | |||||
break; | |||||
/* 40 G */ | /* 40 G */ | ||||
case I40E_PHY_TYPE_40GBASE_CR4: | case I40E_PHY_TYPE_40GBASE_CR4: | ||||
case I40E_PHY_TYPE_40GBASE_CR4_CU: | case I40E_PHY_TYPE_40GBASE_CR4_CU: | ||||
ifmr->ifm_active |= IFM_40G_CR4; | ifmr->ifm_active |= IFM_40G_CR4; | ||||
break; | break; | ||||
case I40E_PHY_TYPE_40GBASE_SR4: | case I40E_PHY_TYPE_40GBASE_SR4: | ||||
ifmr->ifm_active |= IFM_40G_SR4; | ifmr->ifm_active |= IFM_40G_SR4; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | ixl_media_status(struct ifnet * ifp, struct ifmediareq * ifmr) | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
} | } | ||||
void | void | ||||
ixl_init(void *arg) | ixl_init(void *arg) | ||||
{ | { | ||||
struct ixl_pf *pf = arg; | struct ixl_pf *pf = arg; | ||||
struct ixl_vsi *vsi = &pf->vsi; | |||||
device_t dev = pf->dev; | |||||
int error = 0; | |||||
/* | |||||
* If the aq is dead here, it probably means something outside of the driver | |||||
* did something to the adapter, like a PF reset. | |||||
* So rebuild the driver's state here if that occurs. | |||||
*/ | |||||
if (!i40e_check_asq_alive(&pf->hw)) { | |||||
device_printf(dev, "Admin Queue is down; resetting...\n"); | |||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
ixl_teardown_hw_structs(pf); | |||||
ixl_reset(pf); | |||||
IXL_PF_UNLOCK(pf); | |||||
} | |||||
/* | |||||
* Set up LAN queue interrupts here. | |||||
* Kernel interrupt setup functions cannot be called while holding a lock, | |||||
* so this is done outside of init_locked(). | |||||
*/ | |||||
if (pf->msix > 1) { | |||||
/* Teardown existing interrupts, if they exist */ | |||||
ixl_teardown_queue_msix(vsi); | |||||
ixl_free_queue_tqs(vsi); | |||||
/* Then set them up again */ | |||||
error = ixl_setup_queue_msix(vsi); | |||||
if (error) | |||||
device_printf(dev, "ixl_setup_queue_msix() error: %d\n", | |||||
error); | |||||
error = ixl_setup_queue_tqs(vsi); | |||||
if (error) | |||||
device_printf(dev, "ixl_setup_queue_tqs() error: %d\n", | |||||
error); | |||||
} else | |||||
// possibly broken | |||||
error = ixl_assign_vsi_legacy(pf); | |||||
if (error) { | |||||
device_printf(pf->dev, "assign_vsi_msix/legacy error: %d\n", error); | |||||
return; | |||||
} | |||||
IXL_PF_LOCK(pf); | |||||
ixl_init_locked(pf); | ixl_init_locked(pf); | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
} | } | ||||
/* | /* | ||||
* NOTE: Fortville does not support forcing media speeds. Instead, | * NOTE: Fortville does not support forcing media speeds. Instead, | ||||
* use the set_advertise sysctl to set the speeds Fortville | * use the set_advertise sysctl to set the speeds Fortville | ||||
* will advertise or be allowed to operate at. | * will advertise or be allowed to operate at. | ||||
Show All 34 Lines | #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; | ||||
switch (command) { | switch (command) { | ||||
case SIOCSIFADDR: | case SIOCSIFADDR: | ||||
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) | ||||
avoid_reset = TRUE; | avoid_reset = TRUE; | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (ifp->if_flags & IFF_UP) { | ||||
} | } | ||||
} else { | } else { | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
ixl_init(pf); | ixl_init(pf); | ||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
} | } | ||||
} else { | } else { | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | ||||
IXL_PF_UNLOCK(pf); | ixl_stop_locked(pf); | ||||
ixl_stop(pf); | |||||
IXL_PF_LOCK(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"); | ||||
/* NVM update command */ | /* NVM update command */ | ||||
if (ifd->ifd_cmd == I40E_NVM_ACCESS) | if (ifd->ifd_cmd == I40E_NVM_ACCESS) | ||||
error = ixl_handle_nvmupd_cmd(pf, ifd); | error = ixl_handle_nvmupd_cmd(pf, ifd); | ||||
else | else | ||||
error = EINVAL; | error = EINVAL; | ||||
break; | break; | ||||
case SIOCADDMULTI: | case SIOCADDMULTI: | ||||
IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); | IOCTL_DEBUGOUT("ioctl: SIOCADDMULTI"); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | ||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
ixl_disable_intr(vsi); | ixl_disable_rings_intr(vsi); | ||||
ixl_add_multi(vsi); | ixl_add_multi(vsi); | ||||
ixl_enable_intr(vsi); | ixl_enable_intr(vsi); | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
} | } | ||||
break; | break; | ||||
case SIOCDELMULTI: | case SIOCDELMULTI: | ||||
IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); | IOCTL_DEBUGOUT("ioctl: SIOCDELMULTI"); | ||||
if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | ||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
ixl_disable_intr(vsi); | ixl_disable_rings_intr(vsi); | ||||
ixl_del_multi(vsi); | ixl_del_multi(vsi); | ||||
ixl_enable_intr(vsi); | ixl_enable_intr(vsi); | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
} | } | ||||
break; | break; | ||||
case SIOCSIFMEDIA: | case SIOCSIFMEDIA: | ||||
case SIOCGIFMEDIA: | case SIOCGIFMEDIA: | ||||
case SIOCGIFXMEDIA: | case SIOCGIFXMEDIA: | ||||
Show All 23 Lines | if (ifp->if_drv_flags & IFF_DRV_RUNNING) { | ||||
IXL_PF_LOCK(pf); | IXL_PF_LOCK(pf); | ||||
ixl_init_locked(pf); | ixl_init_locked(pf); | ||||
IXL_PF_UNLOCK(pf); | IXL_PF_UNLOCK(pf); | ||||
} | } | ||||
VLAN_CAPABILITIES(ifp); | VLAN_CAPABILITIES(ifp); | ||||
break; | break; | ||||
} | } | ||||
#if __FreeBSD_version >= 1003000 | |||||
case SIOCGI2C: | |||||
{ | |||||
struct ifi2creq i2c; | |||||
int i; | |||||
IOCTL_DEBUGOUT("ioctl: SIOCGI2C (Get I2C Data)"); | |||||
if (!pf->has_i2c) | |||||
return (ENOTTY); | |||||
error = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); | |||||
if (error != 0) | |||||
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->ifr_data, sizeof(i2c)); | |||||
break; | |||||
} | |||||
#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); | ||||
} | } | ||||
int | |||||
ixl_find_i2c_interface(struct ixl_pf *pf) | |||||
{ | |||||
struct i40e_hw *hw = &pf->hw; | |||||
bool i2c_en, port_matched; | |||||
u32 reg; | |||||
for (int i = 0; i < 4; i++) { | |||||
reg = rd32(hw, I40E_GLGEN_MDIO_I2C_SEL(i)); | |||||
i2c_en = (reg & I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_MASK); | |||||
port_matched = ((reg & I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_MASK) | |||||
>> I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT) | |||||
& BIT(hw->port); | |||||
if (i2c_en && port_matched) | |||||
return (i); | |||||
} | |||||
return (-1); | |||||
} | |||||
static char * | static char * | ||||
ixl_phy_type_string(u32 bit_pos) | ixl_phy_type_string(u32 bit_pos, bool ext) | ||||
{ | { | ||||
static char * phy_types_str[32] = { | static char * phy_types_str[32] = { | ||||
"SGMII", | "SGMII", | ||||
"1000BASE-KX", | "1000BASE-KX", | ||||
"10GBASE-KX4", | "10GBASE-KX4", | ||||
"10GBASE-KR", | "10GBASE-KR", | ||||
"40GBASE-KR4", | "40GBASE-KR4", | ||||
"XAUI", | "XAUI", | ||||
Show All 19 Lines | static char * phy_types_str[32] = { | ||||
"40GBASE-SR4", | "40GBASE-SR4", | ||||
"40GBASE-LR4", | "40GBASE-LR4", | ||||
"1000BASE-SX", | "1000BASE-SX", | ||||
"1000BASE-LX", | "1000BASE-LX", | ||||
"1000BASE-T Optical", | "1000BASE-T Optical", | ||||
"20GBASE-KR2", | "20GBASE-KR2", | ||||
"Reserved (31)" | "Reserved (31)" | ||||
}; | }; | ||||
static char * ext_phy_types_str[4] = { | |||||
"25GBASE-KR", | |||||
"25GBASE-CR", | |||||
"25GBASE-SR", | |||||
"25GBASE-LR" | |||||
}; | |||||
if (ext && bit_pos > 3) return "Invalid_Ext"; | |||||
if (bit_pos > 31) return "Invalid"; | if (bit_pos > 31) return "Invalid"; | ||||
return phy_types_str[bit_pos]; | |||||
return (ext) ? ext_phy_types_str[bit_pos] : phy_types_str[bit_pos]; | |||||
} | } | ||||
int | |||||
ixl_aq_get_link_status(struct ixl_pf *pf, struct i40e_aqc_get_link_status *link_status) | |||||
{ | |||||
device_t dev = pf->dev; | |||||
struct i40e_hw *hw = &pf->hw; | |||||
struct i40e_aq_desc desc; | |||||
enum i40e_status_code status; | |||||
struct i40e_aqc_get_link_status *aq_link_status = | |||||
(struct i40e_aqc_get_link_status *)&desc.params.raw; | |||||
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_get_link_status); | |||||
link_status->command_flags = CPU_TO_LE16(I40E_AQ_LSE_ENABLE); | |||||
status = i40e_asq_send_command(hw, &desc, NULL, 0, NULL); | |||||
if (status) { | |||||
device_printf(dev, | |||||
"%s: i40e_aqc_opc_get_link_status status %s, aq error %s\n", | |||||
__func__, i40e_stat_str(hw, status), | |||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | |||||
return (EIO); | |||||
} | |||||
bcopy(aq_link_status, link_status, sizeof(struct i40e_aqc_get_link_status)); | |||||
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; | ||||
struct i40e_hw *hw = &pf->hw; | |||||
device_t dev = pf->dev; | device_t dev = pf->dev; | ||||
struct i40e_link_status link_status; | |||||
enum i40e_status_code status; | |||||
struct sbuf *buf; | struct sbuf *buf; | ||||
int error = 0; | int error = 0; | ||||
buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); | buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); | ||||
if (!buf) { | if (!buf) { | ||||
device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); | device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
status = i40e_aq_get_link_info(hw, true, &link_status, NULL); | struct i40e_aqc_get_link_status link_status; | ||||
if (status) { | error = ixl_aq_get_link_status(pf, &link_status); | ||||
device_printf(dev, | if (error) { | ||||
"%s: i40e_aq_get_link_info() status %s, aq error %s\n", | |||||
__func__, i40e_stat_str(hw, status), | |||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | |||||
sbuf_delete(buf); | sbuf_delete(buf); | ||||
return (EIO); | return (error); | ||||
} | } | ||||
/* TODO: Add 25G types */ | |||||
sbuf_printf(buf, "\n" | sbuf_printf(buf, "\n" | ||||
"PHY Type : 0x%02x<%s>\n" | "PHY Type : 0x%02x<%s>\n" | ||||
"Speed : 0x%02x\n" | "Speed : 0x%02x\n" | ||||
"Link info: 0x%02x\n" | "Link info: 0x%02x\n" | ||||
"AN info : 0x%02x\n" | "AN info : 0x%02x\n" | ||||
"Ext info : 0x%02x\n" | "Ext info : 0x%02x\n" | ||||
"Loopback : 0x%02x\n" | |||||
"Max Frame: %d\n" | "Max Frame: %d\n" | ||||
"Pacing : 0x%02x\n" | "Config : 0x%02x\n" | ||||
"CRC En? : %s\n", | "Power : 0x%02x", | ||||
link_status.phy_type, ixl_phy_type_string(link_status.phy_type), | link_status.phy_type, | ||||
ixl_phy_type_string_ls(link_status.phy_type), | |||||
link_status.link_speed, | link_status.link_speed, | ||||
link_status.link_info, link_status.an_info, | link_status.link_info, | ||||
link_status.ext_info, link_status.max_frame_size, | link_status.an_info, | ||||
link_status.pacing, | link_status.ext_info, | ||||
(link_status.crc_enable) ? "Yes" : "No"); | link_status.loopback, | ||||
link_status.max_frame_size, | |||||
link_status.config, | |||||
link_status.power_desc); | |||||
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); | ||||
} | } | ||||
Show All 11 Lines | ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS) | ||||
buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); | buf = sbuf_new_for_sysctl(NULL, NULL, 128, req); | ||||
if (!buf) { | if (!buf) { | ||||
device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); | device_printf(dev, "Could not allocate sbuf for sysctl output.\n"); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
status = i40e_aq_get_phy_capabilities(hw, | status = i40e_aq_get_phy_capabilities(hw, | ||||
TRUE, FALSE, &abilities, NULL); | FALSE, FALSE, &abilities, NULL); | ||||
if (status) { | if (status) { | ||||
device_printf(dev, | device_printf(dev, | ||||
"%s: i40e_aq_get_phy_capabilities() status %s, aq error %s\n", | "%s: i40e_aq_get_phy_capabilities() status %s, aq error %s\n", | ||||
__func__, i40e_stat_str(hw, status), | __func__, i40e_stat_str(hw, status), | ||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | i40e_aq_str(hw, hw->aq.asq_last_status)); | ||||
sbuf_delete(buf); | sbuf_delete(buf); | ||||
return (EIO); | return (EIO); | ||||
} | } | ||||
sbuf_printf(buf, "\n" | 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)); | sbuf_printf(buf, "%s,", ixl_phy_type_string(i, false)); | ||||
sbuf_printf(buf, ">\n"); | sbuf_printf(buf, ">\n"); | ||||
} | } | ||||
sbuf_printf(buf, "PHY Ext : %02x", | |||||
abilities.phy_type_ext); | |||||
if (abilities.phy_type_ext != 0) { | |||||
sbuf_printf(buf, "<"); | |||||
for (int i = 0; i < 4; i++) | |||||
if ((1 << i) & abilities.phy_type_ext) | |||||
sbuf_printf(buf, "%s,", ixl_phy_type_string(i, true)); | |||||
sbuf_printf(buf, ">"); | |||||
} | |||||
sbuf_printf(buf, "\n"); | |||||
sbuf_printf(buf, | sbuf_printf(buf, | ||||
"Speed : %02x\n" | "Speed : %02x\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", | "ModType : %02x %02x %02x\n" | ||||
"ModType E: %01x\n" | |||||
"FEC Cfg : %02x\n" | |||||
"Ext CC : %02x", | |||||
abilities.link_speed, | 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.module_type[2], abilities.phy_type_ext >> 5, | ||||
abilities.phy_type_ext & 0x1F, | |||||
abilities.ext_comp_code); | |||||
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); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Longest string length: 25 | * Longest string length: 25 | ||||
*/ | */ | ||||
char * | char * | ||||
ixl_switch_res_type_string(u8 type) | ixl_switch_res_type_string(u8 type) | ||||
{ | { | ||||
char * ixl_switch_res_type_strings[0x14] = { | static char * ixl_switch_res_type_strings[0x14] = { | ||||
"VEB", | "VEB", | ||||
"VSI", | "VSI", | ||||
"Perfect Match MAC address", | "Perfect Match MAC address", | ||||
"S-tag", | "S-tag", | ||||
"(Reserved)", | "(Reserved)", | ||||
"Multicast hash entry", | "Multicast hash entry", | ||||
"Unicast hash entry", | "Unicast hash entry", | ||||
"VLAN", | "VLAN", | ||||
▲ Show 20 Lines • Show All 285 Lines • ▼ Show 20 Lines | ixl_sysctl_hlut(SYSCTL_HANDLER_ARGS) | ||||
} | } | ||||
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 | |||||
ixl_sysctl_hena(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
struct i40e_hw *hw = &pf->hw; | |||||
u64 hena; | |||||
hena = (u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(0)) | | |||||
((u64)i40e_read_rx_ctl(hw, I40E_PFQF_HENA(1)) << 32); | |||||
return sysctl_handle_long(oidp, NULL, hena, req); | |||||
} | |||||
/* | |||||
* Sysctl to disable firmware's link management | |||||
* | |||||
* 1 - Disable link management on this port | |||||
* 0 - Re-enable link management | |||||
* | |||||
* On normal NVMs, firmware manages link by default. | |||||
*/ | |||||
static int | |||||
ixl_sysctl_fw_link_management(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
struct i40e_hw *hw = &pf->hw; | |||||
device_t dev = pf->dev; | |||||
int requested_mode = -1; | |||||
enum i40e_status_code status = 0; | |||||
int error = 0; | |||||
/* Read in new mode */ | |||||
error = sysctl_handle_int(oidp, &requested_mode, 0, req); | |||||
if ((error) || (req->newptr == NULL)) | |||||
return (error); | |||||
/* Check for sane value */ | |||||
if (requested_mode < 0 || requested_mode > 1) { | |||||
device_printf(dev, "Valid modes are 0 or 1\n"); | |||||
return (EINVAL); | |||||
} | |||||
/* Set new mode */ | |||||
status = i40e_aq_set_phy_debug(hw, !!(requested_mode) << 4, NULL); | |||||
if (status) { | |||||
device_printf(dev, | |||||
"%s: Error setting new phy debug mode %s," | |||||
" aq error: %s\n", __func__, i40e_stat_str(hw, status), | |||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | |||||
return (EIO); | |||||
} | |||||
return (0); | |||||
} | |||||
/* | |||||
* Sysctl to read a byte from I2C bus. | |||||
* | |||||
* Input: 32-bit value: | |||||
* bits 0-7: device address (0xA0 or 0xA2) | |||||
* bits 8-15: offset (0-255) | |||||
* bits 16-31: unused | |||||
* Output: 8-bit value read | |||||
*/ | |||||
static int | |||||
ixl_sysctl_read_i2c_byte(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
device_t dev = pf->dev; | |||||
int input = -1, error = 0; | |||||
device_printf(dev, "%s: start\n", __func__); | |||||
u8 dev_addr, offset, output; | |||||
/* Read in I2C read parameters */ | |||||
error = sysctl_handle_int(oidp, &input, 0, req); | |||||
if ((error) || (req->newptr == NULL)) | |||||
return (error); | |||||
/* Validate device address */ | |||||
dev_addr = input & 0xFF; | |||||
if (dev_addr != 0xA0 && dev_addr != 0xA2) { | |||||
return (EINVAL); | |||||
} | |||||
offset = (input >> 8) & 0xFF; | |||||
error = ixl_read_i2c_byte(pf, offset, dev_addr, &output); | |||||
if (error) | |||||
return (error); | |||||
device_printf(dev, "%02X\n", output); | |||||
return (0); | |||||
} | |||||
/* | |||||
* Sysctl to write a byte to the I2C bus. | |||||
* | |||||
* Input: 32-bit value: | |||||
* bits 0-7: device address (0xA0 or 0xA2) | |||||
* bits 8-15: offset (0-255) | |||||
* bits 16-23: value to write | |||||
* bits 24-31: unused | |||||
* Output: 8-bit value written | |||||
*/ | |||||
static int | |||||
ixl_sysctl_write_i2c_byte(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
device_t dev = pf->dev; | |||||
int input = -1, error = 0; | |||||
u8 dev_addr, offset, value; | |||||
/* Read in I2C write parameters */ | |||||
error = sysctl_handle_int(oidp, &input, 0, req); | |||||
if ((error) || (req->newptr == NULL)) | |||||
return (error); | |||||
/* Validate device address */ | |||||
dev_addr = input & 0xFF; | |||||
if (dev_addr != 0xA0 && dev_addr != 0xA2) { | |||||
return (EINVAL); | |||||
} | |||||
offset = (input >> 8) & 0xFF; | |||||
value = (input >> 16) & 0xFF; | |||||
error = ixl_write_i2c_byte(pf, offset, dev_addr, value); | |||||
if (error) | |||||
return (error); | |||||
device_printf(dev, "%02X written\n", value); | |||||
return (0); | |||||
} | |||||
static int | |||||
ixl_get_fec_config(struct ixl_pf *pf, struct i40e_aq_get_phy_abilities_resp *abilities, | |||||
u8 bit_pos, int *is_set) | |||||
{ | |||||
device_t dev = pf->dev; | |||||
struct i40e_hw *hw = &pf->hw; | |||||
enum i40e_status_code status; | |||||
status = i40e_aq_get_phy_capabilities(hw, | |||||
FALSE, FALSE, abilities, NULL); | |||||
if (status) { | |||||
device_printf(dev, | |||||
"%s: i40e_aq_get_phy_capabilities() status %s, aq error %s\n", | |||||
__func__, i40e_stat_str(hw, status), | |||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | |||||
return (EIO); | |||||
} | |||||
*is_set = !!(abilities->phy_type_ext & bit_pos); | |||||
return (0); | |||||
} | |||||
static int | |||||
ixl_set_fec_config(struct ixl_pf *pf, struct i40e_aq_get_phy_abilities_resp *abilities, | |||||
u8 bit_pos, int set) | |||||
{ | |||||
device_t dev = pf->dev; | |||||
struct i40e_hw *hw = &pf->hw; | |||||
struct i40e_aq_set_phy_config config; | |||||
enum i40e_status_code status; | |||||
/* Set new PHY config */ | |||||
memset(&config, 0, sizeof(config)); | |||||
config.fec_config = abilities->phy_type_ext & ~(bit_pos); | |||||
if (set) | |||||
config.fec_config |= bit_pos; | |||||
if (config.fec_config != abilities->phy_type_ext) { | |||||
config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK; | |||||
config.phy_type = abilities->phy_type; | |||||
config.phy_type_ext = abilities->phy_type_ext; | |||||
config.link_speed = abilities->link_speed; | |||||
config.eee_capability = abilities->eee_capability; | |||||
config.eeer = abilities->eeer_val; | |||||
config.low_power_ctrl = abilities->d3_lpan; | |||||
status = i40e_aq_set_phy_config(hw, &config, NULL); | |||||
if (status) { | |||||
device_printf(dev, | |||||
"%s: i40e_aq_set_phy_config() status %s, aq error %s\n", | |||||
__func__, i40e_stat_str(hw, status), | |||||
i40e_aq_str(hw, hw->aq.asq_last_status)); | |||||
return (EIO); | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
ixl_sysctl_fec_fc_ability(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
int mode, error = 0; | |||||
struct i40e_aq_get_phy_abilities_resp abilities; | |||||
error = ixl_get_fec_config(pf, &abilities, I40E_AQ_SET_FEC_ABILITY_KR, &mode); | |||||
if (error) | |||||
return (error); | |||||
/* Read in new mode */ | |||||
error = sysctl_handle_int(oidp, &mode, 0, req); | |||||
if ((error) || (req->newptr == NULL)) | |||||
return (error); | |||||
return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_ABILITY_KR, !!(mode)); | |||||
} | |||||
static int | |||||
ixl_sysctl_fec_rs_ability(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
int mode, error = 0; | |||||
struct i40e_aq_get_phy_abilities_resp abilities; | |||||
error = ixl_get_fec_config(pf, &abilities, I40E_AQ_SET_FEC_ABILITY_RS, &mode); | |||||
if (error) | |||||
return (error); | |||||
/* Read in new mode */ | |||||
error = sysctl_handle_int(oidp, &mode, 0, req); | |||||
if ((error) || (req->newptr == NULL)) | |||||
return (error); | |||||
return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_ABILITY_RS, !!(mode)); | |||||
} | |||||
static int | |||||
ixl_sysctl_fec_fc_request(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
int mode, error = 0; | |||||
struct i40e_aq_get_phy_abilities_resp abilities; | |||||
error = ixl_get_fec_config(pf, &abilities, I40E_AQ_SET_FEC_REQUEST_KR, &mode); | |||||
if (error) | |||||
return (error); | |||||
/* Read in new mode */ | |||||
error = sysctl_handle_int(oidp, &mode, 0, req); | |||||
if ((error) || (req->newptr == NULL)) | |||||
return (error); | |||||
return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_REQUEST_KR, !!(mode)); | |||||
} | |||||
static int | |||||
ixl_sysctl_fec_rs_request(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
int mode, error = 0; | |||||
struct i40e_aq_get_phy_abilities_resp abilities; | |||||
error = ixl_get_fec_config(pf, &abilities, I40E_AQ_SET_FEC_REQUEST_RS, &mode); | |||||
if (error) | |||||
return (error); | |||||
/* Read in new mode */ | |||||
error = sysctl_handle_int(oidp, &mode, 0, req); | |||||
if ((error) || (req->newptr == NULL)) | |||||
return (error); | |||||
return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_REQUEST_RS, !!(mode)); | |||||
} | |||||
static int | |||||
ixl_sysctl_fec_auto_enable(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
struct ixl_pf *pf = (struct ixl_pf *)arg1; | |||||
int mode, error = 0; | |||||
struct i40e_aq_get_phy_abilities_resp abilities; | |||||
error = ixl_get_fec_config(pf, &abilities, I40E_AQ_SET_FEC_AUTO, &mode); | |||||
if (error) | |||||
return (error); | |||||
/* Read in new mode */ | |||||
error = sysctl_handle_int(oidp, &mode, 0, req); | |||||
if ((error) || (req->newptr == NULL)) | |||||
return (error); | |||||
return ixl_set_fec_config(pf, &abilities, I40E_AQ_SET_FEC_AUTO, !!(mode)); | |||||
} | } | ||||