Print this page
NEX-20178 Heavy read load using 10G i40e causes network disconnect
MFV illumos-joyent@83a8d0d616db36010b59cc850d1926c0f6a30de1
OS-7457 i40e Tx freezes on zero descriptors
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
MFV illumos-joyent@0d3f2b61dcfb18edace4fd257054f6fdbe07c99c
OS-7492 i40e Tx freeze when b_cont chain exceeds 8 descriptors
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
MFV illumos-joyent@b4bede175d4c50ac1b36078a677b69388f6fb59f
OS-7577 initialize FC for i40e
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Rob Johnston <rob.johnston@joyent.com>
MFV illumos-joyent@83a8d0d616db36010b59cc850d1926c0f6a30de1
OS-7457 i40e Tx freezes on zero descriptors
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
NEX-19928 i40e: cannot create static IP address
Reviewed by: Cynthia Eastham <cynthia.eastham@nexenta.com>
MFV: illumos-joyent@b93056a35d6d6d301f24bc6631fc57dd2c8992c4
OS-7456 i40e default VSI sometimes lacks implicit L2 filter
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Author: Ryan Zezeski <rpz@joyent.com>
MFV: illumos-joyent@61dc3dec4f82a3e13e94609a0a83d5f66c64e760
OS-6846 want i40e multi-group support
OS-7372 i40e_alloc_ring_mem() unwinds when it shouldn't
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Author: Ryan Zezeski <rpz@joyent.com>
MFV: illumos-joyent@9e30beee2f0c127bf41868db46257124206e28d6
OS-5225 Want Fortville TSO support
Reviewed by: Ryan Zezeski <rpz@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Patrick Mooney <patrick.mooney@joyent.com>
Author: Rob Johnston <rob.johnston@joyent.com>
NEX-7822 40Gb Intel XL710 NIC performance data
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
*** 9,19 ****
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
! * Copyright (c) 2017, Joyent, Inc.
* Copyright 2017 Tegile Systems, Inc. All rights reserved.
*/
/*
* i40e - Intel 10/40 Gb Ethernet driver
--- 9,19 ----
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
! * Copyright 2019 Joyent, Inc.
* Copyright 2017 Tegile Systems, Inc. All rights reserved.
*/
/*
* i40e - Intel 10/40 Gb Ethernet driver
*** 135,145 ****
* For each unique PCI device that we encounter, we'll create a i40e_device_t.
* From there, because we don't have a good way to tell the GLDv3 about sharing
* resources between everything, we'll end up just dividing the resources
* evenly between all of the functions. Longer term, if we don't have to declare
* to the GLDv3 that these resources are shared, then we'll maintain a pool and
! * hae each PF allocate from the pool in the device, thus if only two of four
* ports are being used, for example, then all of the resources can still be
* used.
*
* -------------------------------------------
* Transmit and Receive Queue Pair Allocations
--- 135,145 ----
* For each unique PCI device that we encounter, we'll create a i40e_device_t.
* From there, because we don't have a good way to tell the GLDv3 about sharing
* resources between everything, we'll end up just dividing the resources
* evenly between all of the functions. Longer term, if we don't have to declare
* to the GLDv3 that these resources are shared, then we'll maintain a pool and
! * have each PF allocate from the pool in the device, thus if only two of four
* ports are being used, for example, then all of the resources can still be
* used.
*
* -------------------------------------------
* Transmit and Receive Queue Pair Allocations
*** 167,177 ****
* the default VSI.
*
* To receieve broadcast traffic, we enable it through the admin queue, rather
* than use one of our filters for it. For multicast traffic, we reserve a
* certain number of the hash filters and assign them to a given PF. When we
! * exceed those, we then switch to using promicuous mode for multicast traffic.
*
* More specifically, once we exceed the number of filters (indicated because
* the i40e_t`i40e_resources.ifr_nmcastfilt ==
* i40e_t`i40e_resources.ifr_nmcastfilt_used), we then instead need to toggle
* promiscuous mode. If promiscuous mode is toggled then we keep track of the
--- 167,177 ----
* the default VSI.
*
* To receieve broadcast traffic, we enable it through the admin queue, rather
* than use one of our filters for it. For multicast traffic, we reserve a
* certain number of the hash filters and assign them to a given PF. When we
! * exceed those, we then switch to using promiscuous mode for multicast traffic.
*
* More specifically, once we exceed the number of filters (indicated because
* the i40e_t`i40e_resources.ifr_nmcastfilt ==
* i40e_t`i40e_resources.ifr_nmcastfilt_used), we then instead need to toggle
* promiscuous mode. If promiscuous mode is toggled then we keep track of the
*** 186,203 ****
*
* --------------
* VSI Management
* --------------
*
! * At this time, we currently only support a single MAC group, and thus a single
! * VSI. This VSI is considered the default VSI and should be the only one that
! * exists after a reset. Currently it is stored as the member
! * i40e_t`i40e_vsi_id. While this works for the moment and for an initial
! * driver, it's not sufficient for the longer-term path of the driver. Instead,
! * we'll want to actually have a unique i40e_vsi_t structure which is used
! * everywhere. Note that this means that every place that uses the
! * i40e_t`i40e_vsi_id will need to be refactored.
*
* ----------------
* Structure Layout
* ----------------
*
--- 186,204 ----
*
* --------------
* VSI Management
* --------------
*
! * The PFs share 384 VSIs. The firmware creates one VSI per PF by default.
! * During chip start we retrieve the SEID of this VSI and assign it as the
! * default VSI for our VEB (one VEB per PF). We then add additional VSIs to
! * the VEB up to the determined number of rx groups: i40e_t`i40e_num_rx_groups.
! * We currently cap this number to I40E_GROUP_MAX to a) make sure all PFs can
! * allocate the same number of VSIs, and b) to keep the interrupt multiplexing
! * under control. In the future, when we improve the interrupt allocation, we
! * may want to revisit this cap to make better use of the available VSIs. The
! * VSI allocation and configuration can be found in i40e_chip_start().
*
* ----------------
* Structure Layout
* ----------------
*
*** 238,261 ****
* | i40e_device_t * --+-----+
* | i40e_state_t --+---> Device State
* | i40e_hw_t --+---> Intel common code structure
* | mac_handle_t --+---> GLDv3 handle to MAC
* | ddi_periodic_t --+---> Link activity timer
! * | int (vsi_id) --+---> VSI ID, main identifier
* | i40e_func_rsrc_t --+---> Available hardware resources
* | i40e_switch_rsrc_t * --+---> Switch resource snapshot
* | i40e_sdu --+---> Current MTU
* | i40e_frame_max --+---> Current HW frame size
* | i40e_uaddr_t * --+---> Array of assigned unicast MACs
* | i40e_maddr_t * --+---> Array of assigned multicast MACs
* | i40e_mcast_promisccount --+---> Active multicast state
* | i40e_promisc_on --+---> Current promiscuous mode state
! * | int --+---> Number of transmit/receive pairs
* | kstat_t * --+---> PF kstats
- * | kstat_t * --+---> VSI kstats
* | i40e_pf_stats_t --+---> PF kstat backing data
- * | i40e_vsi_stats_t --+---> VSI kstat backing data
* | i40e_trqpair_t * --+---------+
* +---------------------------+ |
* |
* v
* +-------------------------------+ +-----------------------------+
--- 239,261 ----
* | i40e_device_t * --+-----+
* | i40e_state_t --+---> Device State
* | i40e_hw_t --+---> Intel common code structure
* | mac_handle_t --+---> GLDv3 handle to MAC
* | ddi_periodic_t --+---> Link activity timer
! * | i40e_vsi_t * --+---> Array of VSIs
* | i40e_func_rsrc_t --+---> Available hardware resources
* | i40e_switch_rsrc_t * --+---> Switch resource snapshot
* | i40e_sdu --+---> Current MTU
* | i40e_frame_max --+---> Current HW frame size
* | i40e_uaddr_t * --+---> Array of assigned unicast MACs
* | i40e_maddr_t * --+---> Array of assigned multicast MACs
* | i40e_mcast_promisccount --+---> Active multicast state
* | i40e_promisc_on --+---> Current promiscuous mode state
! * | uint_t --+---> Number of transmit/receive pairs
! * | i40e_rx_group_t * --+---> Array of Rx groups
* | kstat_t * --+---> PF kstats
* | i40e_pf_stats_t --+---> PF kstat backing data
* | i40e_trqpair_t * --+---------+
* +---------------------------+ |
* |
* v
* +-------------------------------+ +-----------------------------+
*** 357,368 ****
* At the moment the i40e_t driver is rather bare bones, allowing us to start
* getting data flowing and folks using it while we develop additional features.
* While bugs have been filed to cover this future work, the following gives an
* overview of expected work:
*
- * o TSO support
- * o Multiple group support
* o DMA binding and breaking up the locking in ring recycling.
* o Enhanced detection of device errors
* o Participation in IRM
* o FMA device reset
* o Stall detection, temperature error detection, etc.
--- 357,366 ----
*** 369,379 ****
* o More dynamic resource pools
*/
#include "i40e_sw.h"
! static char i40e_ident[] = "Intel 10/40Gb Ethernet v1.0.1";
/*
* The i40e_glock primarily protects the lists below and the i40e_device_t
* structures.
*/
--- 367,377 ----
* o More dynamic resource pools
*/
#include "i40e_sw.h"
! static char i40e_ident[] = "Intel 10/40Gb Ethernet v1.0.3";
/*
* The i40e_glock primarily protects the lists below and the i40e_device_t
* structures.
*/
*** 759,777 ****
FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
}
}
/*
! * Here we're trying to get the ID of the default VSI. In general, when we come
! * through and look at this shortly after attach, we expect there to only be a
! * single element present, which is the default VSI. Importantly, each PF seems
! * to not see any other devices, in part because of the simple switch mode that
! * we're using. If for some reason, we see more artifact, we'll need to revisit
! * what we're doing here.
*/
! static int
! i40e_get_vsi_id(i40e_t *i40e)
{
i40e_hw_t *hw = &i40e->i40e_hw_space;
struct i40e_aqc_get_switch_config_resp *sw_config;
uint8_t aq_buf[I40E_AQ_LARGE_BUF];
uint16_t next = 0;
--- 757,776 ----
FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
}
}
/*
! * Here we're trying to set the SEID of the default VSI. In general,
! * when we come through and look at this shortly after attach, we
! * expect there to only be a single element present, which is the
! * default VSI. Importantly, each PF seems to not see any other
! * devices, in part because of the simple switch mode that we're
! * using. If for some reason, we see more artifacts, we'll need to
! * revisit what we're doing here.
*/
! static boolean_t
! i40e_set_def_vsi_seid(i40e_t *i40e)
{
i40e_hw_t *hw = &i40e->i40e_hw_space;
struct i40e_aqc_get_switch_config_resp *sw_config;
uint8_t aq_buf[I40E_AQ_LARGE_BUF];
uint16_t next = 0;
*** 782,802 ****
rc = i40e_aq_get_switch_config(hw, sw_config, sizeof (aq_buf), &next,
NULL);
if (rc != I40E_SUCCESS) {
i40e_error(i40e, "i40e_aq_get_switch_config() failed %d: %d",
rc, hw->aq.asq_last_status);
! return (-1);
}
if (LE_16(sw_config->header.num_reported) != 1) {
i40e_error(i40e, "encountered multiple (%d) switching units "
"during attach, not proceeding",
LE_16(sw_config->header.num_reported));
return (-1);
}
! return (sw_config->element[0].seid);
}
/*
* We need to fill the i40e_hw_t structure with the capabilities of this PF. We
* must also provide the memory for it; however, we don't need to keep it around
--- 781,827 ----
rc = i40e_aq_get_switch_config(hw, sw_config, sizeof (aq_buf), &next,
NULL);
if (rc != I40E_SUCCESS) {
i40e_error(i40e, "i40e_aq_get_switch_config() failed %d: %d",
rc, hw->aq.asq_last_status);
! return (B_FALSE);
}
if (LE_16(sw_config->header.num_reported) != 1) {
i40e_error(i40e, "encountered multiple (%d) switching units "
"during attach, not proceeding",
LE_16(sw_config->header.num_reported));
+ return (B_FALSE);
+ }
+
+ I40E_DEF_VSI_SEID(i40e) = sw_config->element[0].seid;
+ return (B_TRUE);
+ }
+
+ /*
+ * Get the SEID of the uplink MAC.
+ */
+ static int
+ i40e_get_mac_seid(i40e_t *i40e)
+ {
+ i40e_hw_t *hw = &i40e->i40e_hw_space;
+ struct i40e_aqc_get_switch_config_resp *sw_config;
+ uint8_t aq_buf[I40E_AQ_LARGE_BUF];
+ uint16_t next = 0;
+ int rc;
+
+ /* LINTED: E_BAD_PTR_CAST_ALIGN */
+ sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
+ rc = i40e_aq_get_switch_config(hw, sw_config, sizeof (aq_buf), &next,
+ NULL);
+ if (rc != I40E_SUCCESS) {
+ i40e_error(i40e, "i40e_aq_get_switch_config() failed %d: %d",
+ rc, hw->aq.asq_last_status);
return (-1);
}
! return (LE_16(sw_config->element[0].uplink_seid));
}
/*
* We need to fill the i40e_hw_t structure with the capabilities of this PF. We
* must also provide the memory for it; however, we don't need to keep it around
*** 1096,1110 ****
* Free receive & transmit rings.
*/
static void
i40e_free_trqpairs(i40e_t *i40e)
{
- int i;
i40e_trqpair_t *itrq;
if (i40e->i40e_trqpairs != NULL) {
! for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
itrq = &i40e->i40e_trqpairs[i];
mutex_destroy(&itrq->itrq_rx_lock);
mutex_destroy(&itrq->itrq_tx_lock);
mutex_destroy(&itrq->itrq_tcb_lock);
--- 1121,1140 ----
* Free receive & transmit rings.
*/
static void
i40e_free_trqpairs(i40e_t *i40e)
{
i40e_trqpair_t *itrq;
+ if (i40e->i40e_rx_groups != NULL) {
+ kmem_free(i40e->i40e_rx_groups,
+ sizeof (i40e_rx_group_t) * i40e->i40e_num_rx_groups);
+ i40e->i40e_rx_groups = NULL;
+ }
+
if (i40e->i40e_trqpairs != NULL) {
! for (uint_t i = 0; i < i40e->i40e_num_trqpairs; i++) {
itrq = &i40e->i40e_trqpairs[i];
mutex_destroy(&itrq->itrq_rx_lock);
mutex_destroy(&itrq->itrq_tx_lock);
mutex_destroy(&itrq->itrq_tcb_lock);
*** 1131,1141 ****
* need.
*/
static boolean_t
i40e_alloc_trqpairs(i40e_t *i40e)
{
- int i;
void *mutexpri = DDI_INTR_PRI(i40e->i40e_intr_pri);
/*
* Now that we have the priority for the interrupts, initialize
* all relevant locks.
--- 1161,1170 ----
*** 1144,1182 ****
mutex_init(&i40e->i40e_rx_pending_lock, NULL, MUTEX_DRIVER, mutexpri);
cv_init(&i40e->i40e_rx_pending_cv, NULL, CV_DRIVER, NULL);
i40e->i40e_trqpairs = kmem_zalloc(sizeof (i40e_trqpair_t) *
i40e->i40e_num_trqpairs, KM_SLEEP);
! for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i];
itrq->itrq_i40e = i40e;
mutex_init(&itrq->itrq_rx_lock, NULL, MUTEX_DRIVER, mutexpri);
mutex_init(&itrq->itrq_tx_lock, NULL, MUTEX_DRIVER, mutexpri);
mutex_init(&itrq->itrq_tcb_lock, NULL, MUTEX_DRIVER, mutexpri);
itrq->itrq_index = i;
}
return (B_TRUE);
}
/*
* Unless a .conf file already overrode i40e_t structure values, they will
* be 0, and need to be set in conjunction with the now-available HW report.
- *
- * However, at the moment, we cap all of these resources as we only support a
- * single receive ring and a single group.
*/
/* ARGSUSED */
static void
i40e_hw_to_instance(i40e_t *i40e, i40e_hw_t *hw)
{
! if (i40e->i40e_num_trqpairs == 0) {
! i40e->i40e_num_trqpairs = I40E_TRQPAIR_MAX;
}
if (i40e->i40e_num_rx_groups == 0) {
i40e->i40e_num_rx_groups = I40E_GROUP_MAX;
}
}
--- 1173,1224 ----
mutex_init(&i40e->i40e_rx_pending_lock, NULL, MUTEX_DRIVER, mutexpri);
cv_init(&i40e->i40e_rx_pending_cv, NULL, CV_DRIVER, NULL);
i40e->i40e_trqpairs = kmem_zalloc(sizeof (i40e_trqpair_t) *
i40e->i40e_num_trqpairs, KM_SLEEP);
! for (uint_t i = 0; i < i40e->i40e_num_trqpairs; i++) {
i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i];
itrq->itrq_i40e = i40e;
mutex_init(&itrq->itrq_rx_lock, NULL, MUTEX_DRIVER, mutexpri);
mutex_init(&itrq->itrq_tx_lock, NULL, MUTEX_DRIVER, mutexpri);
mutex_init(&itrq->itrq_tcb_lock, NULL, MUTEX_DRIVER, mutexpri);
itrq->itrq_index = i;
}
+ i40e->i40e_rx_groups = kmem_zalloc(sizeof (i40e_rx_group_t) *
+ i40e->i40e_num_rx_groups, KM_SLEEP);
+
+ for (uint_t i = 0; i < i40e->i40e_num_rx_groups; i++) {
+ i40e_rx_group_t *rxg = &i40e->i40e_rx_groups[i];
+
+ rxg->irg_index = i;
+ rxg->irg_i40e = i40e;
+ }
+
return (B_TRUE);
}
/*
* Unless a .conf file already overrode i40e_t structure values, they will
* be 0, and need to be set in conjunction with the now-available HW report.
*/
/* ARGSUSED */
static void
i40e_hw_to_instance(i40e_t *i40e, i40e_hw_t *hw)
{
! if (i40e->i40e_num_trqpairs_per_vsi == 0) {
! if (i40e_is_x722(i40e)) {
! i40e->i40e_num_trqpairs_per_vsi =
! I40E_722_MAX_TC_QUEUES;
! } else {
! i40e->i40e_num_trqpairs_per_vsi =
! I40E_710_MAX_TC_QUEUES;
}
+ }
if (i40e->i40e_num_rx_groups == 0) {
i40e->i40e_num_rx_groups = I40E_GROUP_MAX;
}
}
*** 1307,1322 ****
rc);
return (B_FALSE);
}
/*
! * We need to obtain the Virtual Station ID (VSI) before we can
! * perform other operations on the device.
*/
! i40e->i40e_vsi_id = i40e_get_vsi_id(i40e);
! if (i40e->i40e_vsi_id == -1) {
! i40e_error(i40e, "failed to obtain VSI ID");
return (B_FALSE);
}
return (B_TRUE);
}
--- 1349,1363 ----
rc);
return (B_FALSE);
}
/*
! * We need to obtain the Default Virtual Station SEID (VSI)
! * before we can perform other operations on the device.
*/
! if (!i40e_set_def_vsi_seid(i40e)) {
! i40e_error(i40e, "failed to obtain Default VSI SEID");
return (B_FALSE);
}
return (B_TRUE);
}
*** 1557,1566 ****
--- 1598,1610 ----
I40E_DEF_RX_LIMIT_PER_INTR);
i40e->i40e_tx_hcksum_enable = i40e_get_prop(i40e, "tx_hcksum_enable",
B_FALSE, B_TRUE, B_TRUE);
+ i40e->i40e_tx_lso_enable = i40e_get_prop(i40e, "tx_lso_enable",
+ B_FALSE, B_TRUE, B_TRUE);
+
i40e->i40e_rx_hcksum_enable = i40e_get_prop(i40e, "rx_hcksum_enable",
B_FALSE, B_TRUE, B_TRUE);
i40e->i40e_rx_dma_min = i40e_get_prop(i40e, "rx_dma_threshold",
I40E_MIN_RX_DMA_THRESH, I40E_MAX_RX_DMA_THRESH,
*** 1726,1752 ****
rc);
return (B_FALSE);
}
i40e->i40e_intr_type = 0;
if ((intr_types & DDI_INTR_TYPE_MSIX) &&
! i40e->i40e_intr_force <= I40E_INTR_MSIX) {
! if (i40e_alloc_intr_handles(i40e, devinfo,
! DDI_INTR_TYPE_MSIX)) {
! i40e->i40e_num_trqpairs =
! MIN(i40e->i40e_intr_count - 1, max_trqpairs);
return (B_TRUE);
}
- }
/*
* We only use multiple transmit/receive pairs when MSI-X interrupts are
* available due to the fact that the device basically only supports a
* single MSI interrupt.
*/
i40e->i40e_num_trqpairs = I40E_TRQPAIR_NOMSIX;
i40e->i40e_num_rx_groups = I40E_GROUP_NOMSIX;
if ((intr_types & DDI_INTR_TYPE_MSI) &&
(i40e->i40e_intr_force <= I40E_INTR_MSI)) {
if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSI))
--- 1770,1838 ----
rc);
return (B_FALSE);
}
i40e->i40e_intr_type = 0;
+ i40e->i40e_num_rx_groups = I40E_GROUP_MAX;
+ /*
+ * We need to determine the number of queue pairs per traffic
+ * class. We only have one traffic class (TC0), so we'll base
+ * this off the number of interrupts provided. Furthermore,
+ * since we only use one traffic class, the number of queues
+ * per traffic class and per VSI are the same.
+ */
if ((intr_types & DDI_INTR_TYPE_MSIX) &&
! (i40e->i40e_intr_force <= I40E_INTR_MSIX) &&
! (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSIX))) {
! uint32_t n;
!
! /*
! * While we want the number of queue pairs to match
! * the number of interrupts, we must keep stay in
! * bounds of the maximum number of queues per traffic
! * class. We subtract one from i40e_intr_count to
! * account for interrupt zero; which is currently
! * restricted to admin queue commands and other
! * interrupt causes.
! */
! n = MIN(i40e->i40e_intr_count - 1, max_trqpairs);
! ASSERT3U(n, >, 0);
!
! /*
! * Round up to the nearest power of two to ensure that
! * the QBASE aligns with the TC size which must be
! * programmed as a power of two. See the queue mapping
! * description in section 7.4.9.5.5.1.
! *
! * If i40e_intr_count - 1 is not a power of two then
! * some queue pairs on the same VSI will have to share
! * an interrupt.
! *
! * We may want to revisit this logic in a future where
! * we have more interrupts and more VSIs. Otherwise,
! * each VSI will use as many interrupts as possible.
! * Using more QPs per VSI means better RSS for each
! * group, but at the same time may require more
! * sharing of interrupts across VSIs. This may be a
! * good candidate for a .conf tunable.
! */
! n = 0x1 << ddi_fls(n);
! i40e->i40e_num_trqpairs_per_vsi = n;
! ASSERT3U(i40e->i40e_num_rx_groups, >, 0);
! i40e->i40e_num_trqpairs = i40e->i40e_num_trqpairs_per_vsi *
! i40e->i40e_num_rx_groups;
return (B_TRUE);
}
/*
* We only use multiple transmit/receive pairs when MSI-X interrupts are
* available due to the fact that the device basically only supports a
* single MSI interrupt.
*/
i40e->i40e_num_trqpairs = I40E_TRQPAIR_NOMSIX;
+ i40e->i40e_num_trqpairs_per_vsi = i40e->i40e_num_trqpairs;
i40e->i40e_num_rx_groups = I40E_GROUP_NOMSIX;
if ((intr_types & DDI_INTR_TYPE_MSI) &&
(i40e->i40e_intr_force <= I40E_INTR_MSI)) {
if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSI))
*** 1765,1792 ****
* Map different interrupts to MSI-X vectors.
*/
static boolean_t
i40e_map_intrs_to_vectors(i40e_t *i40e)
{
- int i;
-
if (i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) {
return (B_TRUE);
}
/*
! * Each queue pair is mapped to a single interrupt, so transmit
! * and receive interrupts for a given queue share the same vector.
! * The number of queue pairs is one less than the number of interrupt
! * vectors and is assigned the vector one higher than its index.
! * Vector zero is reserved for the admin queue.
*/
! ASSERT(i40e->i40e_intr_count == i40e->i40e_num_trqpairs + 1);
! for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
! i40e->i40e_trqpairs[i].itrq_rx_intrvec = i + 1;
! i40e->i40e_trqpairs[i].itrq_tx_intrvec = i + 1;
}
return (B_TRUE);
}
--- 1851,1874 ----
* Map different interrupts to MSI-X vectors.
*/
static boolean_t
i40e_map_intrs_to_vectors(i40e_t *i40e)
{
if (i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) {
return (B_TRUE);
}
/*
! * Each queue pair is mapped to a single interrupt, so
! * transmit and receive interrupts for a given queue share the
! * same vector. Vector zero is reserved for the admin queue.
*/
! for (uint_t i = 0; i < i40e->i40e_num_trqpairs; i++) {
! uint_t vector = i % (i40e->i40e_intr_count - 1);
! i40e->i40e_trqpairs[i].itrq_rx_intrvec = vector + 1;
! i40e->i40e_trqpairs[i].itrq_tx_intrvec = vector + 1;
}
return (B_TRUE);
}
*** 1921,2030 ****
i40e_init_macaddrs(i40e_t *i40e, i40e_hw_t *hw)
{
}
/*
! * Configure the hardware for the Virtual Station Interface (VSI). Currently
! * we only support one, but in the future we could instantiate more than one
! * per attach-point.
*/
! static boolean_t
! i40e_config_vsi(i40e_t *i40e, i40e_hw_t *hw)
{
! struct i40e_vsi_context context;
! int err, tc_queues;
! bzero(&context, sizeof (struct i40e_vsi_context));
! context.seid = i40e->i40e_vsi_id;
! context.pf_num = hw->pf_id;
! err = i40e_aq_get_vsi_params(hw, &context, NULL);
! if (err != I40E_SUCCESS) {
! i40e_error(i40e, "get VSI params failed with %d", err);
! return (B_FALSE);
! }
- i40e->i40e_vsi_num = context.vsi_number;
-
/*
! * Set the queue and traffic class bits. Keep it simple for now.
*/
! context.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
! context.info.mapping_flags = I40E_AQ_VSI_QUE_MAP_CONTIG;
! context.info.queue_mapping[0] = I40E_ASSIGN_ALL_QUEUES;
/*
! * tc_queues determines the size of the traffic class, where the size is
! * 2^^tc_queues to a maximum of 64 for the X710 and 128 for the X722.
*
* Some examples:
! * i40e_num_trqpairs == 1 => tc_queues = 0, 2^^0 = 1.
! * i40e_num_trqpairs == 7 => tc_queues = 3, 2^^3 = 8.
! * i40e_num_trqpairs == 8 => tc_queues = 3, 2^^3 = 8.
! * i40e_num_trqpairs == 9 => tc_queues = 4, 2^^4 = 16.
! * i40e_num_trqpairs == 17 => tc_queues = 5, 2^^5 = 32.
! * i40e_num_trqpairs == 64 => tc_queues = 6, 2^^6 = 64.
*/
! tc_queues = ddi_fls(i40e->i40e_num_trqpairs - 1);
! context.info.tc_mapping[0] = ((0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) &
I40E_AQ_VSI_TC_QUE_OFFSET_MASK) |
((tc_queues << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT) &
! I40E_AQ_VSI_TC_QUE_NUMBER_MASK);
! context.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
! context.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
! context.flags = LE16_TO_CPU(I40E_AQ_VSI_TYPE_PF);
! i40e->i40e_vsi_stat_id = LE16_TO_CPU(context.info.stat_counter_idx);
! if (i40e_stat_vsi_init(i40e) == B_FALSE)
! return (B_FALSE);
! err = i40e_aq_update_vsi_params(hw, &context, NULL);
! if (err != I40E_SUCCESS) {
! i40e_error(i40e, "Update VSI params failed with %d", err);
return (B_FALSE);
}
return (B_TRUE);
}
/*
! * Configure the RSS key. For the X710 controller family, this is set on a
! * per-PF basis via registers. For the X722, this is done on a per-VSI basis
! * through the admin queue.
*/
static boolean_t
! i40e_config_rss_key(i40e_t *i40e, i40e_hw_t *hw)
{
! uint32_t seed[I40E_PFQF_HKEY_MAX_INDEX + 1];
! (void) random_get_pseudo_bytes((uint8_t *)seed, sizeof (seed));
! if (i40e_is_x722(i40e)) {
struct i40e_aqc_get_set_rss_key_data key;
! const char *u8seed = (char *)seed;
enum i40e_status_code status;
CTASSERT(sizeof (key) >= (sizeof (key.standard_rss_key) +
sizeof (key.extended_hash_key)));
bcopy(u8seed, key.standard_rss_key,
sizeof (key.standard_rss_key));
bcopy(&u8seed[sizeof (key.standard_rss_key)],
key.extended_hash_key, sizeof (key.extended_hash_key));
! status = i40e_aq_set_rss_key(hw, i40e->i40e_vsi_num, &key);
if (status != I40E_SUCCESS) {
! i40e_error(i40e, "failed to set rss key: %d", status);
return (B_FALSE);
}
} else {
! uint_t i;
! for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), seed[i]);
}
return (B_TRUE);
}
--- 2003,2326 ----
i40e_init_macaddrs(i40e_t *i40e, i40e_hw_t *hw)
{
}
/*
! * Set the properties which have common values across all the VSIs.
! * Consult the "Add VSI" command section (7.4.9.5.5.1) for a
! * complete description of these properties.
*/
! static void
! i40e_set_shared_vsi_props(i40e_t *i40e,
! struct i40e_aqc_vsi_properties_data *info, uint_t vsi_idx)
{
! uint_t tc_queues;
! uint16_t vsi_qp_base;
! /*
! * It's important that we use bitwise-OR here; callers to this
! * function might enable other sections before calling this
! * function.
! */
! info->valid_sections |= LE_16(I40E_AQ_VSI_PROP_QUEUE_MAP_VALID |
! I40E_AQ_VSI_PROP_VLAN_VALID);
/*
! * Calculate the starting QP index for this VSI. This base is
! * relative to the PF queue space; so a value of 0 for PF#1
! * represents the absolute index PFLAN_QALLOC_FIRSTQ for PF#1.
*/
! vsi_qp_base = vsi_idx * i40e->i40e_num_trqpairs_per_vsi;
! info->mapping_flags = LE_16(I40E_AQ_VSI_QUE_MAP_CONTIG);
! info->queue_mapping[0] =
! LE_16((vsi_qp_base << I40E_AQ_VSI_QUEUE_SHIFT) &
! I40E_AQ_VSI_QUEUE_MASK);
/*
! * tc_queues determines the size of the traffic class, where
! * the size is 2^^tc_queues to a maximum of 64 for the X710
! * and 128 for the X722.
*
* Some examples:
! * i40e_num_trqpairs_per_vsi == 1 => tc_queues = 0, 2^^0 = 1.
! * i40e_num_trqpairs_per_vsi == 7 => tc_queues = 3, 2^^3 = 8.
! * i40e_num_trqpairs_per_vsi == 8 => tc_queues = 3, 2^^3 = 8.
! * i40e_num_trqpairs_per_vsi == 9 => tc_queues = 4, 2^^4 = 16.
! * i40e_num_trqpairs_per_vsi == 17 => tc_queues = 5, 2^^5 = 32.
! * i40e_num_trqpairs_per_vsi == 64 => tc_queues = 6, 2^^6 = 64.
*/
! tc_queues = ddi_fls(i40e->i40e_num_trqpairs_per_vsi - 1);
! /*
! * The TC queue mapping is in relation to the VSI queue space.
! * Since we are only using one traffic class (TC0) we always
! * start at queue offset 0.
! */
! info->tc_mapping[0] =
! LE_16(((0 << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) &
I40E_AQ_VSI_TC_QUE_OFFSET_MASK) |
((tc_queues << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT) &
! I40E_AQ_VSI_TC_QUE_NUMBER_MASK));
! /*
! * I40E_AQ_VSI_PVLAN_MODE_ALL ("VLAN driver insertion mode")
! *
! * Allow tagged and untagged packets to be sent to this
! * VSI from the host.
! *
! * I40E_AQ_VSI_PVLAN_EMOD_NOTHING ("VLAN and UP expose mode")
! *
! * Leave the tag on the frame and place no VLAN
! * information in the descriptor. We want this mode
! * because our MAC layer will take care of the VLAN tag,
! * if there is one.
! */
! info->port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
+ }
! /*
! * Delete the VSI at this index, if one exists. We assume there is no
! * action we can take if this command fails but to log the failure.
! */
! static void
! i40e_delete_vsi(i40e_t *i40e, uint_t idx)
! {
! i40e_hw_t *hw = &i40e->i40e_hw_space;
! uint16_t seid = i40e->i40e_vsis[idx].iv_seid;
! if (seid != 0) {
! int rc;
! rc = i40e_aq_delete_element(hw, seid, NULL);
!
! if (rc != I40E_SUCCESS) {
! i40e_error(i40e, "Failed to delete VSI %d: %d",
! rc, hw->aq.asq_last_status);
! }
!
! i40e->i40e_vsis[idx].iv_seid = 0;
! }
! }
!
! /*
! * Add a new VSI.
! */
! static boolean_t
! i40e_add_vsi(i40e_t *i40e, i40e_hw_t *hw, uint_t idx)
! {
! struct i40e_vsi_context ctx;
! i40e_rx_group_t *rxg;
! int rc;
!
! /*
! * The default VSI is created by the controller. This function
! * creates new, non-defualt VSIs only.
! */
! ASSERT3U(idx, !=, 0);
!
! bzero(&ctx, sizeof (struct i40e_vsi_context));
! ctx.uplink_seid = i40e->i40e_veb_seid;
! ctx.pf_num = hw->pf_id;
! ctx.flags = I40E_AQ_VSI_TYPE_PF;
! ctx.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL;
! i40e_set_shared_vsi_props(i40e, &ctx.info, idx);
!
! rc = i40e_aq_add_vsi(hw, &ctx, NULL);
! if (rc != I40E_SUCCESS) {
! i40e_error(i40e, "i40e_aq_add_vsi() failed %d: %d", rc,
! hw->aq.asq_last_status);
return (B_FALSE);
}
+ rxg = &i40e->i40e_rx_groups[idx];
+ rxg->irg_vsi_seid = ctx.seid;
+ i40e->i40e_vsis[idx].iv_number = ctx.vsi_number;
+ i40e->i40e_vsis[idx].iv_seid = ctx.seid;
+ i40e->i40e_vsis[idx].iv_stats_id = LE_16(ctx.info.stat_counter_idx);
+ if (i40e_stat_vsi_init(i40e, idx) == B_FALSE)
+ return (B_FALSE);
+
return (B_TRUE);
}
/*
! * Configure the hardware for the Default Virtual Station Interface (VSI).
*/
static boolean_t
! i40e_config_def_vsi(i40e_t *i40e, i40e_hw_t *hw)
{
! struct i40e_vsi_context ctx;
! i40e_rx_group_t *def_rxg;
! int err;
! struct i40e_aqc_remove_macvlan_element_data filt;
! bzero(&ctx, sizeof (struct i40e_vsi_context));
! ctx.seid = I40E_DEF_VSI_SEID(i40e);
! ctx.pf_num = hw->pf_id;
! err = i40e_aq_get_vsi_params(hw, &ctx, NULL);
! if (err != I40E_SUCCESS) {
! i40e_error(i40e, "get VSI params failed with %d", err);
! return (B_FALSE);
! }
! ctx.info.valid_sections = 0;
! i40e->i40e_vsis[0].iv_number = ctx.vsi_number;
! i40e->i40e_vsis[0].iv_stats_id = LE_16(ctx.info.stat_counter_idx);
! if (i40e_stat_vsi_init(i40e, 0) == B_FALSE)
! return (B_FALSE);
!
! i40e_set_shared_vsi_props(i40e, &ctx.info, I40E_DEF_VSI_IDX);
!
! err = i40e_aq_update_vsi_params(hw, &ctx, NULL);
! if (err != I40E_SUCCESS) {
! i40e_error(i40e, "Update VSI params failed with %d", err);
! return (B_FALSE);
! }
!
! def_rxg = &i40e->i40e_rx_groups[0];
! def_rxg->irg_vsi_seid = I40E_DEF_VSI_SEID(i40e);
!
! /*
! * We have seen three different behaviors in regards to the
! * Default VSI and its implicit L2 MAC+VLAN filter.
! *
! * 1. It has an implicit filter for the factory MAC address
! * and this filter counts against 'ifr_nmacfilt_used'.
! *
! * 2. It has an implicit filter for the factory MAC address
! * and this filter DOES NOT count against 'ifr_nmacfilt_used'.
! *
! * 3. It DOES NOT have an implicit filter.
! *
! * All three of these cases are accounted for below. If we
! * fail to remove the L2 filter (ENOENT) then we assume there
! * wasn't one. Otherwise, if we successfully remove the
! * filter, we make sure to update the 'ifr_nmacfilt_used'
! * count accordingly.
! *
! * We remove this filter to prevent duplicate delivery of
! * packets destined for the primary MAC address as DLS will
! * create the same filter on a non-default VSI for the primary
! * MAC client.
! *
! * If you change the following code please test it across as
! * many X700 series controllers and firmware revisions as you
! * can.
! */
! bzero(&filt, sizeof (filt));
! bcopy(hw->mac.port_addr, filt.mac_addr, ETHERADDRL);
! filt.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
! filt.vlan_tag = 0;
!
! ASSERT3U(i40e->i40e_resources.ifr_nmacfilt_used, <=, 1);
! i40e_log(i40e, "Num L2 filters: %u",
! i40e->i40e_resources.ifr_nmacfilt_used);
!
! err = i40e_aq_remove_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt, 1,
! NULL);
! if (err == I40E_SUCCESS) {
! i40e_log(i40e,
! "Removed L2 filter from Default VSI with SEID %u",
! I40E_DEF_VSI_SEID(i40e));
! } else if (hw->aq.asq_last_status == ENOENT) {
! i40e_log(i40e,
! "No L2 filter for Default VSI with SEID %u",
! I40E_DEF_VSI_SEID(i40e));
! } else {
! i40e_error(i40e, "Failed to remove L2 filter from"
! " Default VSI with SEID %u: %d (%d)",
! I40E_DEF_VSI_SEID(i40e), err, hw->aq.asq_last_status);
!
! return (B_FALSE);
! }
!
! /*
! * As mentioned above, the controller created an implicit L2
! * filter for the primary MAC. We want to remove both the
! * filter and decrement the filter count. However, not all
! * controllers count this implicit filter against the total
! * MAC filter count. So here we are making sure it is either
! * one or zero. If it is one, then we know it is for the
! * implicit filter and we should decrement since we just
! * removed the filter above. If it is zero then we know the
! * controller that does not count the implicit filter, and it
! * was enough to just remove it; we leave the count alone.
! * But if it is neither, then we have never seen a controller
! * like this before and we should fail to attach.
! *
! * It is unfortunate that this code must exist but the
! * behavior of this implicit L2 filter and its corresponding
! * count were dicovered through empirical testing. The
! * programming manuals hint at this filter but do not
! * explicitly call out the exact behavior.
! */
! if (i40e->i40e_resources.ifr_nmacfilt_used == 1) {
! i40e->i40e_resources.ifr_nmacfilt_used--;
! } else {
! if (i40e->i40e_resources.ifr_nmacfilt_used != 0) {
! i40e_error(i40e, "Unexpected L2 filter count: %u"
! " (expected 0)",
! i40e->i40e_resources.ifr_nmacfilt_used);
! return (B_FALSE);
! }
! }
!
! return (B_TRUE);
! }
!
! static boolean_t
! i40e_config_rss_key_x722(i40e_t *i40e, i40e_hw_t *hw)
! {
! for (uint_t i = 0; i < i40e->i40e_num_rx_groups; i++) {
! uint32_t seed[I40E_PFQF_HKEY_MAX_INDEX + 1];
struct i40e_aqc_get_set_rss_key_data key;
! const char *u8seed;
enum i40e_status_code status;
+ uint16_t vsi_number = i40e->i40e_vsis[i].iv_number;
+ (void) random_get_pseudo_bytes((uint8_t *)seed, sizeof (seed));
+ u8seed = (char *)seed;
+
CTASSERT(sizeof (key) >= (sizeof (key.standard_rss_key) +
sizeof (key.extended_hash_key)));
bcopy(u8seed, key.standard_rss_key,
sizeof (key.standard_rss_key));
bcopy(&u8seed[sizeof (key.standard_rss_key)],
key.extended_hash_key, sizeof (key.extended_hash_key));
! ASSERT3U(vsi_number, !=, 0);
! status = i40e_aq_set_rss_key(hw, vsi_number, &key);
!
if (status != I40E_SUCCESS) {
! i40e_error(i40e, "failed to set RSS key for VSI %u: %d",
! vsi_number, status);
return (B_FALSE);
}
+ }
+
+ return (B_TRUE);
+ }
+
+ /*
+ * Configure the RSS key. For the X710 controller family, this is set on a
+ * per-PF basis via registers. For the X722, this is done on a per-VSI basis
+ * through the admin queue.
+ */
+ static boolean_t
+ i40e_config_rss_key(i40e_t *i40e, i40e_hw_t *hw)
+ {
+ if (i40e_is_x722(i40e)) {
+ if (!i40e_config_rss_key_x722(i40e, hw))
+ return (B_FALSE);
} else {
! uint32_t seed[I40E_PFQF_HKEY_MAX_INDEX + 1];
!
! (void) random_get_pseudo_bytes((uint8_t *)seed, sizeof (seed));
! for (uint_t i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
i40e_write_rx_ctl(hw, I40E_PFQF_HKEY(i), seed[i]);
}
return (B_TRUE);
}
*** 2032,2046 ****
/*
* Populate the LUT. The size of each entry in the LUT depends on the controller
* family, with the X722 using a known 7-bit width. On the X710 controller, this
* is programmed through its control registers where as on the X722 this is
* configured through the admin queue. Also of note, the X722 allows the LUT to
! * be set on a per-PF or VSI basis. At this time, as we only have a single VSI,
! * we use the PF setting as it is the primary VSI.
*
* We populate the LUT in a round robin fashion with the rx queue indices from 0
! * to i40e_num_trqpairs - 1.
*/
static boolean_t
i40e_config_rss_hlut(i40e_t *i40e, i40e_hw_t *hw)
{
uint32_t *hlut;
--- 2328,2343 ----
/*
* Populate the LUT. The size of each entry in the LUT depends on the controller
* family, with the X722 using a known 7-bit width. On the X710 controller, this
* is programmed through its control registers where as on the X722 this is
* configured through the admin queue. Also of note, the X722 allows the LUT to
! * be set on a per-PF or VSI basis. At this time we use the PF setting. If we
! * decide to use the per-VSI LUT in the future, then we will need to modify the
! * i40e_add_vsi() function to set the RSS LUT bits in the queueing section.
*
* We populate the LUT in a round robin fashion with the rx queue indices from 0
! * to i40e_num_trqpairs_per_vsi - 1.
*/
static boolean_t
i40e_config_rss_hlut(i40e_t *i40e, i40e_hw_t *hw)
{
uint32_t *hlut;
*** 2066,2084 ****
lut_mask = (1 << 7) - 1;
} else {
lut_mask = (1 << hw->func_caps.rss_table_entry_width) - 1;
}
! for (i = 0; i < I40E_HLUT_TABLE_SIZE; i++)
! ((uint8_t *)hlut)[i] = (i % i40e->i40e_num_trqpairs) & lut_mask;
if (i40e_is_x722(i40e)) {
enum i40e_status_code status;
! status = i40e_aq_set_rss_lut(hw, i40e->i40e_vsi_num, B_TRUE,
! (uint8_t *)hlut, I40E_HLUT_TABLE_SIZE);
if (status != I40E_SUCCESS) {
! i40e_error(i40e, "failed to set RSS LUT: %d", status);
goto out;
}
} else {
for (i = 0; i < I40E_HLUT_TABLE_SIZE >> 2; i++) {
I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i), hlut[i]);
--- 2363,2386 ----
lut_mask = (1 << 7) - 1;
} else {
lut_mask = (1 << hw->func_caps.rss_table_entry_width) - 1;
}
! for (i = 0; i < I40E_HLUT_TABLE_SIZE; i++) {
! ((uint8_t *)hlut)[i] =
! (i % i40e->i40e_num_trqpairs_per_vsi) & lut_mask;
! }
if (i40e_is_x722(i40e)) {
enum i40e_status_code status;
!
! status = i40e_aq_set_rss_lut(hw, 0, B_TRUE, (uint8_t *)hlut,
! I40E_HLUT_TABLE_SIZE);
!
if (status != I40E_SUCCESS) {
! i40e_error(i40e, "failed to set RSS LUT %d: %d",
! status, hw->aq.asq_last_status);
goto out;
}
} else {
for (i = 0; i < I40E_HLUT_TABLE_SIZE >> 2; i++) {
I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i), hlut[i]);
*** 2150,2159 ****
--- 2452,2462 ----
i40e_chip_start(i40e_t *i40e)
{
i40e_hw_t *hw = &i40e->i40e_hw_space;
struct i40e_filter_control_settings filter;
int rc;
+ uint8_t err;
if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
(hw->aq.fw_maj_ver < 4)) {
i40e_msec_delay(75);
if (i40e_aq_set_link_restart_an(hw, TRUE, NULL) !=
*** 2165,2174 ****
--- 2468,2486 ----
}
/* Determine hardware state */
i40e_get_hw_state(i40e, hw);
+ /* For now, we always disable Ethernet Flow Control. */
+ hw->fc.requested_mode = I40E_FC_NONE;
+ rc = i40e_set_fc(hw, &err, B_TRUE);
+ if (rc != I40E_SUCCESS) {
+ i40e_error(i40e, "Setting flow control failed, returned %d"
+ " with error: 0x%x", rc, err);
+ return (B_FALSE);
+ }
+
/* Initialize mac addresses. */
i40e_init_macaddrs(i40e, hw);
/*
* Set up the filter control. If the hash lut size is changed from
*** 2186,2198 ****
return (B_FALSE);
}
i40e_intr_chip_init(i40e);
! if (!i40e_config_vsi(i40e, hw))
return (B_FALSE);
if (!i40e_config_rss(i40e, hw))
return (B_FALSE);
i40e_flush(hw);
--- 2498,2536 ----
return (B_FALSE);
}
i40e_intr_chip_init(i40e);
! rc = i40e_get_mac_seid(i40e);
! if (rc == -1) {
! i40e_error(i40e, "failed to obtain MAC Uplink SEID");
return (B_FALSE);
+ }
+ i40e->i40e_mac_seid = (uint16_t)rc;
+ /*
+ * Create a VEB in order to support multiple VSIs. Each VSI
+ * functions as a MAC group. This call sets the PF's MAC as
+ * the uplink port and the PF's default VSI as the default
+ * downlink port.
+ */
+ rc = i40e_aq_add_veb(hw, i40e->i40e_mac_seid, I40E_DEF_VSI_SEID(i40e),
+ 0x1, B_TRUE, &i40e->i40e_veb_seid, B_FALSE, NULL);
+ if (rc != I40E_SUCCESS) {
+ i40e_error(i40e, "i40e_aq_add_veb() failed %d: %d", rc,
+ hw->aq.asq_last_status);
+ return (B_FALSE);
+ }
+
+ if (!i40e_config_def_vsi(i40e, hw))
+ return (B_FALSE);
+
+ for (uint_t i = 1; i < i40e->i40e_num_rx_groups; i++) {
+ if (!i40e_add_vsi(i40e, hw, i))
+ return (B_FALSE);
+ }
+
if (!i40e_config_rss(i40e, hw))
return (B_FALSE);
i40e_flush(hw);
*** 2547,2557 ****
* traffic class index for the first device. We query the VSI parameters
* again to get what the handle is. Note that every queue is always
* assigned to traffic class zero, because we don't actually use them.
*/
bzero(&context, sizeof (struct i40e_vsi_context));
! context.seid = i40e->i40e_vsi_id;
context.pf_num = hw->pf_id;
err = i40e_aq_get_vsi_params(hw, &context, NULL);
if (err != I40E_SUCCESS) {
i40e_error(i40e, "get VSI params failed with %d", err);
return (B_FALSE);
--- 2885,2895 ----
* traffic class index for the first device. We query the VSI parameters
* again to get what the handle is. Note that every queue is always
* assigned to traffic class zero, because we don't actually use them.
*/
bzero(&context, sizeof (struct i40e_vsi_context));
! context.seid = I40E_DEF_VSI_SEID(i40e);
context.pf_num = hw->pf_id;
err = i40e_aq_get_vsi_params(hw, &context, NULL);
if (err != I40E_SUCCESS) {
i40e_error(i40e, "get VSI params failed with %d", err);
return (B_FALSE);
*** 2651,2661 ****
}
void
i40e_stop(i40e_t *i40e, boolean_t free_allocations)
{
! int i;
ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
/*
* Shutdown and drain the tx and rx pipeline. We do this using the
--- 2989,3000 ----
}
void
i40e_stop(i40e_t *i40e, boolean_t free_allocations)
{
! uint_t i;
! i40e_hw_t *hw = &i40e->i40e_hw_space;
ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
/*
* Shutdown and drain the tx and rx pipeline. We do this using the
*** 2687,2696 ****
--- 3026,3056 ----
ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
}
delay(50 * drv_usectohz(1000));
+ /*
+ * We don't delete the default VSI because it replaces the VEB
+ * after VEB deletion (see the "Delete Element" section).
+ * Furthermore, since the default VSI is provided by the
+ * firmware, we never attempt to delete it.
+ */
+ for (i = 1; i < i40e->i40e_num_rx_groups; i++) {
+ i40e_delete_vsi(i40e, i);
+ }
+
+ if (i40e->i40e_veb_seid != 0) {
+ int rc = i40e_aq_delete_element(hw, i40e->i40e_veb_seid, NULL);
+
+ if (rc != I40E_SUCCESS) {
+ i40e_error(i40e, "Failed to delete VEB %d: %d", rc,
+ hw->aq.asq_last_status);
+ }
+
+ i40e->i40e_veb_seid = 0;
+ }
+
i40e_intr_chip_fini(i40e);
for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
mutex_enter(&i40e->i40e_trqpairs[i].itrq_rx_lock);
mutex_enter(&i40e->i40e_trqpairs[i].itrq_tx_lock);
*** 2716,2726 ****
for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
mutex_exit(&i40e->i40e_trqpairs[i].itrq_rx_lock);
mutex_exit(&i40e->i40e_trqpairs[i].itrq_tx_lock);
}
! i40e_stat_vsi_fini(i40e);
i40e->i40e_link_speed = 0;
i40e->i40e_link_duplex = 0;
i40e_link_state_set(i40e, LINK_STATE_UNKNOWN);
--- 3076,3088 ----
for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
mutex_exit(&i40e->i40e_trqpairs[i].itrq_rx_lock);
mutex_exit(&i40e->i40e_trqpairs[i].itrq_tx_lock);
}
! for (i = 0; i < i40e->i40e_num_rx_groups; i++) {
! i40e_stat_vsi_fini(i40e, i);
! }
i40e->i40e_link_speed = 0;
i40e->i40e_link_duplex = 0;
i40e_link_state_set(i40e, LINK_STATE_UNKNOWN);
*** 2781,2791 ****
/*
* Enable broadcast traffic; however, do not enable multicast traffic.
* That's handle exclusively through MAC's mc_multicst routines.
*/
! err = i40e_aq_set_vsi_broadcast(hw, i40e->i40e_vsi_id, B_TRUE, NULL);
if (err != I40E_SUCCESS) {
i40e_error(i40e, "failed to set default VSI: %d", err);
rc = B_FALSE;
goto done;
}
--- 3143,3154 ----
/*
* Enable broadcast traffic; however, do not enable multicast traffic.
* That's handle exclusively through MAC's mc_multicst routines.
*/
! err = i40e_aq_set_vsi_broadcast(hw, I40E_DEF_VSI_SEID(i40e), B_TRUE,
! NULL);
if (err != I40E_SUCCESS) {
i40e_error(i40e, "failed to set default VSI: %d", err);
rc = B_FALSE;
goto done;
}