diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_adminq.c | 23 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_adminq.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 41 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_common.c | 29 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_main.c | 261 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_prototype.h | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 93 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40e_adminq.c | 22 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40e_adminq.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h | 41 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 |
16 files changed, 369 insertions, 166 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index ed3902bf249b..34415d342ece 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -33,6 +33,16 @@ static void i40e_resume_aq(struct i40e_hw *hw); /** + * i40e_is_nvm_update_op - return true if this is an NVM update operation + * @desc: API request descriptor + **/ +static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) +{ + return (desc->opcode == i40e_aqc_opc_nvm_erase) || + (desc->opcode == i40e_aqc_opc_nvm_update); +} + +/** * i40e_adminq_init_regs - Initialize AdminQ registers * @hw: pointer to the hardware structure * @@ -585,6 +595,7 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw) /* pre-emptive resource lock release */ i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL); + hw->aq.nvm_busy = false; ret_code = i40e_aq_set_hmc_resource_profile(hw, I40E_HMC_PROFILE_DEFAULT, @@ -708,6 +719,12 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, goto asq_send_command_exit; } + if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n"); + status = I40E_ERR_NVM; + goto asq_send_command_exit; + } + details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); if (cmd_details) { *details = *cmd_details; @@ -835,6 +852,9 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw, hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; } + if (i40e_is_nvm_update_op(desc)) + hw->aq.nvm_busy = true; + /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { @@ -929,6 +949,9 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, e->msg_size); } + if (i40e_is_nvm_update_op(&e->desc)) + hw->aq.nvm_busy = false; + /* Restore the original datalen and buffer address in the desc, * FW updates datalen to indicate the event message * size diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h index 993f7685a911..b1552fbc48a0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h @@ -90,6 +90,7 @@ struct i40e_adminq_info { u16 fw_min_ver; /* firmware minor version */ u16 api_maj_ver; /* api major version */ u16 api_min_ver; /* api minor version */ + bool nvm_busy; struct mutex asq_mutex; /* Send queue lock */ struct mutex arq_mutex; /* Receive queue lock */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 7b6374a8f8da..f2ba4b76ecd3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -182,9 +182,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_add_mirror_rule = 0x0260, i40e_aqc_opc_delete_mirror_rule = 0x0261, - i40e_aqc_opc_set_storm_control_config = 0x0280, - i40e_aqc_opc_get_storm_control_config = 0x0281, - /* DCB commands */ i40e_aqc_opc_dcb_ignore_pfc = 0x0301, i40e_aqc_opc_dcb_updated = 0x0302, @@ -207,6 +204,7 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_query_switching_comp_bw_config = 0x041A, i40e_aqc_opc_suspend_port_tx = 0x041B, i40e_aqc_opc_resume_port_tx = 0x041C, + i40e_aqc_opc_configure_partition_bw = 0x041D, /* hmc */ i40e_aqc_opc_query_hmc_resource_profile = 0x0500, @@ -1289,27 +1287,6 @@ struct i40e_aqc_add_delete_mirror_rule_completion { I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion); -/* Set Storm Control Configuration (direct 0x0280) - * Get Storm Control Configuration (direct 0x0281) - * the command and response use the same descriptor structure - */ -struct i40e_aqc_set_get_storm_control_config { - __le32 broadcast_threshold; - __le32 multicast_threshold; - __le32 control_flags; -#define I40E_AQC_STORM_CONTROL_MDIPW 0x01 -#define I40E_AQC_STORM_CONTROL_MDICW 0x02 -#define I40E_AQC_STORM_CONTROL_BDIPW 0x04 -#define I40E_AQC_STORM_CONTROL_BDICW 0x08 -#define I40E_AQC_STORM_CONTROL_BIDU 0x10 -#define I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT 8 -#define I40E_AQC_STORM_CONTROL_INTERVAL_MASK (0x3FF << \ - I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT) - u8 reserved[4]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_get_storm_control_config); - /* DCB 0x03xx*/ /* PFC Ignore (direct 0x0301) @@ -1499,6 +1476,15 @@ struct i40e_aqc_query_switching_comp_bw_config_resp { * (direct 0x041B and 0x041C) uses the generic SEID struct */ +/* Configure partition BW + * (indirect 0x041D) + */ +struct i40e_aqc_configure_partition_bw_data { + __le16 pf_valid_bits; + u8 min_bw[16]; /* guaranteed bandwidth */ + u8 max_bw[16]; /* bandwidth limit */ +}; + /* Get and set the active HMC resource profile and status. * (direct 0x0500) and (direct 0x0501) */ @@ -1583,11 +1569,8 @@ struct i40e_aq_get_phy_abilities_resp { #define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01 #define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02 #define I40E_AQ_PHY_FLAG_LOW_POWER 0x04 -#define I40E_AQ_PHY_FLAG_AN_SHIFT 3 -#define I40E_AQ_PHY_FLAG_AN_MASK (0x3 << I40E_AQ_PHY_FLAG_AN_SHIFT) -#define I40E_AQ_PHY_FLAG_AN_OFF 0x00 /* link forced on */ -#define I40E_AQ_PHY_FLAG_AN_OFF_LINK_DOWN 0x01 -#define I40E_AQ_PHY_FLAG_AN_ON 0x02 +#define I40E_AQ_PHY_LINK_ENABLED 0x08 +#define I40E_AQ_PHY_AN_ENABLED 0x10 #define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20 __le16 eee_capability; #define I40E_AQ_EEE_100BASE_TX 0x0002 diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 922cdcc45c54..f8dfb4b7e99c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -2253,6 +2253,35 @@ static i40e_status i40e_aq_tx_sched_cmd(struct i40e_hw *hw, u16 seid, } /** + * i40e_aq_config_vsi_bw_limit - Configure VSI BW Limit + * @hw: pointer to the hw struct + * @seid: VSI seid + * @credit: BW limit credits (0 = disabled) + * @max_credit: Max BW limit credits + * @cmd_details: pointer to command details structure or NULL + **/ +i40e_status i40e_aq_config_vsi_bw_limit(struct i40e_hw *hw, + u16 seid, u16 credit, u8 max_credit, + struct i40e_asq_cmd_details *cmd_details) +{ + struct i40e_aq_desc desc; + struct i40e_aqc_configure_vsi_bw_limit *cmd = + (struct i40e_aqc_configure_vsi_bw_limit *)&desc.params.raw; + i40e_status status; + + i40e_fill_default_direct_cmd_desc(&desc, + i40e_aqc_opc_configure_vsi_bw_limit); + + cmd->vsi_seid = cpu_to_le16(seid); + cmd->credit = cpu_to_le16(credit); + cmd->max_credit = max_credit; + + status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details); + + return status; +} + +/** * i40e_aq_config_vsi_tc_bw - Config VSI BW Allocation per TC * @hw: pointer to the hw struct * @seid: VSI seid diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 03d99cbc5c25..0cf47c958081 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -649,7 +649,7 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } rcu_read_lock(); - for (j = 0; j < vsi->num_queue_pairs; j++, i += 4) { + for (j = 0; j < vsi->num_queue_pairs; j++) { struct i40e_ring *tx_ring = ACCESS_ONCE(vsi->tx_rings[j]); struct i40e_ring *rx_ring; @@ -662,14 +662,16 @@ static void i40e_get_ethtool_stats(struct net_device *netdev, data[i] = tx_ring->stats.packets; data[i + 1] = tx_ring->stats.bytes; } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start)); + i += 2; /* Rx ring is the 2nd half of the queue pair */ rx_ring = &tx_ring[1]; do { start = u64_stats_fetch_begin_irq(&rx_ring->syncp); - data[i + 2] = rx_ring->stats.packets; - data[i + 3] = rx_ring->stats.bytes; + data[i] = rx_ring->stats.packets; + data[i + 1] = rx_ring->stats.bytes; } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start)); + i += 2; } rcu_read_unlock(); if (vsi == pf->vsi[pf->lan_vsi]) { @@ -1189,6 +1191,12 @@ static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, return -EINVAL; fsp->flow_type = rule->flow_type; + if (fsp->flow_type == IP_USER_FLOW) { + fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4; + fsp->h_u.usr_ip4_spec.proto = 0; + fsp->m_u.usr_ip4_spec.proto = 0; + } + fsp->h_u.tcp_ip4_spec.psrc = rule->src_port; fsp->h_u.tcp_ip4_spec.pdst = rule->dst_port; fsp->h_u.tcp_ip4_spec.ip4src = rule->src_ip[0]; diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index d5d98fe2691d..5c341aeb5d53 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -747,6 +747,7 @@ static struct i40e_context_ele i40e_hmc_rxq_ce_info[] = { { I40E_HMC_STORE(i40e_hmc_obj_rxq, tphdata_ena), 1, 195 }, { I40E_HMC_STORE(i40e_hmc_obj_rxq, tphhead_ena), 1, 196 }, { I40E_HMC_STORE(i40e_hmc_obj_rxq, lrxqthresh), 3, 198 }, + { I40E_HMC_STORE(i40e_hmc_obj_rxq, prefena), 1, 201 }, { 0 } }; diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h index 341de925a298..eb65fe23c4a7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h @@ -56,6 +56,7 @@ struct i40e_hmc_obj_rxq { u8 tphdata_ena; u8 tphhead_ena; u8 lrxqthresh; + u8 prefena; /* NOTE: normally must be set to 1 at init */ }; /* Tx queue context data */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 861b722c2672..0c69851eaecc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 36 +#define DRV_VERSION_BUILD 43 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN @@ -2312,6 +2312,8 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring) rx_ctx.crcstrip = 1; rx_ctx.l2tsel = 1; rx_ctx.showiv = 1; + /* set the prefena field to 1 because the manual says to */ + rx_ctx.prefena = 1; /* clear the context in the HMC */ err = i40e_clear_lan_rx_queue_context(hw, pf_q); @@ -3163,9 +3165,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) usleep_range(1000, 2000); } /* Skip if the queue is already in the requested state */ - if (enable && (tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) - continue; - if (!enable && !(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) + if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) continue; /* turn on/off the queue */ @@ -3181,13 +3181,8 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) /* wait for the change to finish */ for (j = 0; j < 10; j++) { tx_reg = rd32(hw, I40E_QTX_ENA(pf_q)); - if (enable) { - if ((tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) - break; - } else { - if (!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) - break; - } + if (enable == !!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) + break; udelay(10); } @@ -3226,15 +3221,9 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) usleep_range(1000, 2000); } - if (enable) { - /* is STAT set ? */ - if ((rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) - continue; - } else { - /* is !STAT set ? */ - if (!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) - continue; - } + /* Skip if the queue is already in the requested state */ + if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) + continue; /* turn on/off the queue */ if (enable) @@ -3247,13 +3236,8 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) for (j = 0; j < 10; j++) { rx_reg = rd32(hw, I40E_QRX_ENA(pf_q)); - if (enable) { - if ((rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) - break; - } else { - if (!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) - break; - } + if (enable == !!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK)) + break; udelay(10); } @@ -3516,6 +3500,19 @@ static void i40e_napi_disable_all(struct i40e_vsi *vsi) } /** + * i40e_vsi_close - Shut down a VSI + * @vsi: the vsi to be quelled + **/ +static void i40e_vsi_close(struct i40e_vsi *vsi) +{ + if (!test_and_set_bit(__I40E_DOWN, &vsi->state)) + i40e_down(vsi); + i40e_vsi_free_irq(vsi); + i40e_vsi_free_tx_resources(vsi); + i40e_vsi_free_rx_resources(vsi); +} + +/** * i40e_quiesce_vsi - Pause a given VSI * @vsi: the VSI being paused **/ @@ -3528,8 +3525,7 @@ static void i40e_quiesce_vsi(struct i40e_vsi *vsi) if (vsi->netdev && netif_running(vsi->netdev)) { vsi->netdev->netdev_ops->ndo_stop(vsi->netdev); } else { - set_bit(__I40E_DOWN, &vsi->state); - i40e_down(vsi); + i40e_vsi_close(vsi); } } @@ -3546,7 +3542,7 @@ static void i40e_unquiesce_vsi(struct i40e_vsi *vsi) if (vsi->netdev && netif_running(vsi->netdev)) vsi->netdev->netdev_ops->ndo_open(vsi->netdev); else - i40e_up(vsi); /* this clears the DOWN bit */ + i40e_vsi_open(vsi); /* this clears the DOWN bit */ } /** @@ -4304,24 +4300,32 @@ int i40e_vsi_open(struct i40e_vsi *vsi) if (err) goto err_setup_rx; - if (!vsi->netdev) { + if (vsi->netdev) { + snprintf(int_name, sizeof(int_name) - 1, "%s-%s", + dev_driver_string(&pf->pdev->dev), vsi->netdev->name); + err = i40e_vsi_request_irq(vsi, int_name); + if (err) + goto err_setup_rx; + + /* Notify the stack of the actual queue counts. */ + err = netif_set_real_num_tx_queues(vsi->netdev, + vsi->num_queue_pairs); + if (err) + goto err_set_queues; + + err = netif_set_real_num_rx_queues(vsi->netdev, + vsi->num_queue_pairs); + if (err) + goto err_set_queues; + + } else if (vsi->type == I40E_VSI_FDIR) { + snprintf(int_name, sizeof(int_name) - 1, "%s-fdir", + dev_driver_string(&pf->pdev->dev)); + err = i40e_vsi_request_irq(vsi, int_name); + } else { err = EINVAL; goto err_setup_rx; } - snprintf(int_name, sizeof(int_name) - 1, "%s-%s", - dev_driver_string(&pf->pdev->dev), vsi->netdev->name); - err = i40e_vsi_request_irq(vsi, int_name); - if (err) - goto err_setup_rx; - - /* Notify the stack of the actual queue counts. */ - err = netif_set_real_num_tx_queues(vsi->netdev, vsi->num_queue_pairs); - if (err) - goto err_set_queues; - - err = netif_set_real_num_rx_queues(vsi->netdev, vsi->num_queue_pairs); - if (err) - goto err_set_queues; err = i40e_up_complete(vsi); if (err) @@ -4378,14 +4382,7 @@ static int i40e_close(struct net_device *netdev) struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; - if (test_and_set_bit(__I40E_DOWN, &vsi->state)) - return 0; - - i40e_down(vsi); - i40e_vsi_free_irq(vsi); - - i40e_vsi_free_tx_resources(vsi); - i40e_vsi_free_rx_resources(vsi); + i40e_vsi_close(vsi); return 0; } @@ -5221,9 +5218,6 @@ static int i40e_get_capabilities(struct i40e_pf *pf) } } while (err); - /* increment MSI-X count because current FW skips one */ - pf->hw.func_caps.num_msix_vectors++; - if (((pf->hw.aq.fw_maj_ver == 2) && (pf->hw.aq.fw_min_ver < 22)) || (pf->hw.aq.fw_maj_ver < 2)) { pf->hw.func_caps.num_msix_vectors++; @@ -5262,8 +5256,7 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi); static void i40e_fdir_sb_setup(struct i40e_pf *pf) { struct i40e_vsi *vsi; - bool new_vsi = false; - int err, i; + int i; if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED)) return; @@ -5283,47 +5276,12 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf) pf->vsi[pf->lan_vsi]->seid, 0); if (!vsi) { dev_info(&pf->pdev->dev, "Couldn't create FDir VSI\n"); - goto err_vsi; + pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; + return; } - new_vsi = true; - } - i40e_vsi_setup_irqhandler(vsi, i40e_fdir_clean_ring); - - err = i40e_vsi_setup_tx_resources(vsi); - if (err) - goto err_setup_tx; - err = i40e_vsi_setup_rx_resources(vsi); - if (err) - goto err_setup_rx; - - if (new_vsi) { - char int_name[IFNAMSIZ + 9]; - err = i40e_vsi_configure(vsi); - if (err) - goto err_setup_rx; - snprintf(int_name, sizeof(int_name) - 1, "%s-fdir", - dev_driver_string(&pf->pdev->dev)); - err = i40e_vsi_request_irq(vsi, int_name); - if (err) - goto err_setup_rx; - err = i40e_up_complete(vsi); - if (err) - goto err_up_complete; - clear_bit(__I40E_NEEDS_RESTART, &vsi->state); } - return; - -err_up_complete: - i40e_down(vsi); - i40e_vsi_free_irq(vsi); -err_setup_rx: - i40e_vsi_free_rx_resources(vsi); -err_setup_tx: - i40e_vsi_free_tx_resources(vsi); -err_vsi: - pf->flags &= ~I40E_FLAG_FD_SB_ENABLED; - i40e_vsi_clear(vsi); + i40e_vsi_setup_irqhandler(vsi, i40e_fdir_clean_ring); } /** @@ -6644,6 +6602,96 @@ static void i40e_del_vxlan_port(struct net_device *netdev, } #endif +#ifdef HAVE_FDB_OPS +#ifdef USE_CONST_DEV_UC_CHAR +static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], + struct net_device *dev, + const unsigned char *addr, + u16 flags) +#else +static int i40e_ndo_fdb_add(struct ndmsg *ndm, + struct net_device *dev, + unsigned char *addr, + u16 flags) +#endif +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + struct i40e_pf *pf = np->vsi->back; + int err = 0; + + if (!(pf->flags & I40E_FLAG_SRIOV_ENABLED)) + return -EOPNOTSUPP; + + /* Hardware does not support aging addresses so if a + * ndm_state is given only allow permanent addresses + */ + if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) { + netdev_info(dev, "FDB only supports static addresses\n"); + return -EINVAL; + } + + if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) + err = dev_uc_add_excl(dev, addr); + else if (is_multicast_ether_addr(addr)) + err = dev_mc_add_excl(dev, addr); + else + err = -EINVAL; + + /* Only return duplicate errors if NLM_F_EXCL is set */ + if (err == -EEXIST && !(flags & NLM_F_EXCL)) + err = 0; + + return err; +} + +#ifndef USE_DEFAULT_FDB_DEL_DUMP +#ifdef USE_CONST_DEV_UC_CHAR +static int i40e_ndo_fdb_del(struct ndmsg *ndm, + struct net_device *dev, + const unsigned char *addr) +#else +static int i40e_ndo_fdb_del(struct ndmsg *ndm, + struct net_device *dev, + unsigned char *addr) +#endif +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + struct i40e_pf *pf = np->vsi->back; + int err = -EOPNOTSUPP; + + if (ndm->ndm_state & NUD_PERMANENT) { + netdev_info(dev, "FDB only supports static addresses\n"); + return -EINVAL; + } + + if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { + if (is_unicast_ether_addr(addr)) + err = dev_uc_del(dev, addr); + else if (is_multicast_ether_addr(addr)) + err = dev_mc_del(dev, addr); + else + err = -EINVAL; + } + + return err; +} + +static int i40e_ndo_fdb_dump(struct sk_buff *skb, + struct netlink_callback *cb, + struct net_device *dev, + int idx) +{ + struct i40e_netdev_priv *np = netdev_priv(dev); + struct i40e_pf *pf = np->vsi->back; + + if (pf->flags & I40E_FLAG_SRIOV_ENABLED) + idx = ndo_dflt_fdb_dump(skb, cb, dev, idx); + + return idx; +} + +#endif /* USE_DEFAULT_FDB_DEL_DUMP */ +#endif /* HAVE_FDB_OPS */ static const struct net_device_ops i40e_netdev_ops = { .ndo_open = i40e_open, .ndo_stop = i40e_close, @@ -6671,6 +6719,13 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_add_vxlan_port = i40e_add_vxlan_port, .ndo_del_vxlan_port = i40e_del_vxlan_port, #endif +#ifdef HAVE_FDB_OPS + .ndo_fdb_add = i40e_ndo_fdb_add, +#ifndef USE_DEFAULT_FDB_DEL_DUMP + .ndo_fdb_del = i40e_ndo_fdb_del, + .ndo_fdb_dump = i40e_ndo_fdb_dump, +#endif +#endif }; /** @@ -6976,11 +7031,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi) unregister_netdev(vsi->netdev); } } else { - if (!test_and_set_bit(__I40E_DOWN, &vsi->state)) - i40e_down(vsi); - i40e_vsi_free_irq(vsi); - i40e_vsi_free_tx_resources(vsi); - i40e_vsi_free_rx_resources(vsi); + i40e_vsi_close(vsi); } i40e_vsi_disable_irq(vsi); } @@ -8084,6 +8135,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) u16 link_status; int err = 0; u32 len; + u32 i; err = pci_enable_device_mem(pdev); if (err) @@ -8273,6 +8325,13 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err); goto err_vsis; } + /* if FDIR VSI was set up, start it now */ + for (i = 0; i < pf->hw.func_caps.num_vsis; i++) { + if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) { + i40e_vsi_open(pf->vsi[i]); + break; + } + } /* The main driver is (mostly) up and happy. We need to set this state * before setting up the misc vector or we get a race and the vector diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 9cd57e617959..10652f615aec 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -167,6 +167,9 @@ i40e_status i40e_aq_delete_element(struct i40e_hw *hw, u16 seid, i40e_status i40e_aq_mac_address_write(struct i40e_hw *hw, u16 flags, u8 *mac_addr, struct i40e_asq_cmd_details *cmd_details); +i40e_status i40e_aq_config_vsi_bw_limit(struct i40e_hw *hw, + u16 seid, u16 credit, u8 max_credit, + struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_dcb_updated(struct i40e_hw *hw, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_hmc_resource_profile(struct i40e_hw *hw, diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 02c11a7f7d29..5421714df324 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -29,6 +29,24 @@ /***********************misc routines*****************************/ /** + * i40e_vc_disable_vf + * @pf: pointer to the pf info + * @vf: pointer to the vf info + * + * Disable the VF through a SW reset + **/ +static inline void i40e_vc_disable_vf(struct i40e_pf *pf, struct i40e_vf *vf) +{ + struct i40e_hw *hw = &pf->hw; + u32 reg; + + reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id)); + reg |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; + wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg); + i40e_flush(hw); +} + +/** * i40e_vc_isvalid_vsi_id * @vf: pointer to the vf info * @vsi_id: vf relative vsi id @@ -416,6 +434,15 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) if (ret) dev_err(&pf->pdev->dev, "Unable to program ucast filters\n"); + /* Set VF bandwidth if specified */ + if (vf->tx_rate) { + ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid, + vf->tx_rate / 50, 0, NULL); + if (ret) + dev_err(&pf->pdev->dev, "Unable to set tx rate, VF %d, error code %d.\n", + vf->vf_id, ret); + } + error_alloc_vsi_res: return ret; } @@ -2088,10 +2115,16 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, goto error_pvid; } - if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi)) + if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi)) { dev_err(&pf->pdev->dev, "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n", vf_id); + /* Administrator Error - knock the VF offline until he does + * the right thing by reconfiguring his network correctly + * and then reloading the VF driver. + */ + i40e_vc_disable_vf(pf, vf); + } /* Check for condition where there was already a port VLAN ID * filter set and now it is being deleted by setting it to zero. @@ -2160,7 +2193,61 @@ error_pvid: **/ int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int tx_rate) { - return -EOPNOTSUPP; + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + struct i40e_vsi *vsi; + struct i40e_vf *vf; + int speed = 0; + int ret = 0; + + /* validate the request */ + if (vf_id >= pf->num_alloc_vfs) { + dev_err(&pf->pdev->dev, "Invalid VF Identifier %d.\n", vf_id); + ret = -EINVAL; + goto error; + } + + vf = &(pf->vf[vf_id]); + vsi = pf->vsi[vf->lan_vsi_index]; + if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) { + dev_err(&pf->pdev->dev, "Uninitialized VF %d.\n", vf_id); + ret = -EINVAL; + goto error; + } + + switch (pf->hw.phy.link_info.link_speed) { + case I40E_LINK_SPEED_40GB: + speed = 40000; + break; + case I40E_LINK_SPEED_10GB: + speed = 10000; + break; + case I40E_LINK_SPEED_1GB: + speed = 1000; + break; + default: + break; + } + + if (tx_rate > speed) { + dev_err(&pf->pdev->dev, "Invalid tx rate %d specified for vf %d.", + tx_rate, vf->vf_id); + ret = -EINVAL; + goto error; + } + + /* Tx rate credits are in values of 50Mbps, 0 is disabled*/ + ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid, tx_rate / 50, 0, + NULL); + if (ret) { + dev_err(&pf->pdev->dev, "Unable to set tx rate, error code %d.\n", + ret); + ret = -EIO; + goto error; + } + vf->tx_rate = tx_rate; +error: + return ret; } /** @@ -2200,7 +2287,7 @@ int i40e_ndo_get_vf_config(struct net_device *netdev, memcpy(&ivi->mac, vf->default_lan_addr.addr, ETH_ALEN); - ivi->tx_rate = 0; + ivi->tx_rate = vf->tx_rate; ivi->vlan = le16_to_cpu(vsi->info.pvid) & I40E_VLAN_MASK; ivi->qos = (le16_to_cpu(vsi->info.pvid) & I40E_PRIORITY_MASK) >> I40E_VLAN_PRIORITY_SHIFT; diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 389c47f396d5..ba3d1f8414be 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -98,6 +98,7 @@ struct i40e_vf { unsigned long vf_caps; /* vf's adv. capabilities */ unsigned long vf_states; /* vf's runtime states */ + unsigned int tx_rate; /* Tx bandwidth limit in Mbps */ bool link_forced; bool link_up; /* only valid if vf link is forced */ }; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index 5470ce95936e..c79df257f830 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -28,6 +28,16 @@ #include "i40e_prototype.h" /** + * i40e_is_nvm_update_op - return true if this is an NVM update operation + * @desc: API request descriptor + **/ +static inline bool i40e_is_nvm_update_op(struct i40e_aq_desc *desc) +{ + return (desc->opcode == i40e_aqc_opc_nvm_erase) || + (desc->opcode == i40e_aqc_opc_nvm_update); +} + +/** * i40e_adminq_init_regs - Initialize AdminQ registers * @hw: pointer to the hardware structure * @@ -659,6 +669,12 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, goto asq_send_command_exit; } + if (i40e_is_nvm_update_op(desc) && hw->aq.nvm_busy) { + i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE, "AQTX: NVM busy.\n"); + status = I40E_ERR_NVM; + goto asq_send_command_exit; + } + details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use); if (cmd_details) { *details = *cmd_details; @@ -786,6 +802,9 @@ i40e_status i40evf_asq_send_command(struct i40e_hw *hw, hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval; } + if (i40e_is_nvm_update_op(desc)) + hw->aq.nvm_busy = true; + /* update the error if time out occurred */ if ((!cmd_completed) && (!details->async && !details->postpone)) { @@ -880,6 +899,9 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, e->msg_size); } + if (i40e_is_nvm_update_op(&e->desc)) + hw->aq.nvm_busy = false; + /* Restore the original datalen and buffer address in the desc, * FW updates datalen to indicate the event message * size diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h index 8f72c31d95cc..7d24be528601 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h @@ -87,6 +87,7 @@ struct i40e_adminq_info { u16 fw_min_ver; /* firmware minor version */ u16 api_maj_ver; /* api major version */ u16 api_min_ver; /* api minor version */ + bool nvm_busy; struct mutex asq_mutex; /* Send queue lock */ struct mutex arq_mutex; /* Receive queue lock */ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index 97662b6bd98a..6e617669c326 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -180,9 +180,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_add_mirror_rule = 0x0260, i40e_aqc_opc_delete_mirror_rule = 0x0261, - i40e_aqc_opc_set_storm_control_config = 0x0280, - i40e_aqc_opc_get_storm_control_config = 0x0281, - /* DCB commands */ i40e_aqc_opc_dcb_ignore_pfc = 0x0301, i40e_aqc_opc_dcb_updated = 0x0302, @@ -205,6 +202,7 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_query_switching_comp_bw_config = 0x041A, i40e_aqc_opc_suspend_port_tx = 0x041B, i40e_aqc_opc_resume_port_tx = 0x041C, + i40e_aqc_opc_configure_partition_bw = 0x041D, /* hmc */ i40e_aqc_opc_query_hmc_resource_profile = 0x0500, @@ -1289,27 +1287,6 @@ struct i40e_aqc_add_delete_mirror_rule_completion { I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion); -/* Set Storm Control Configuration (direct 0x0280) - * Get Storm Control Configuration (direct 0x0281) - * the command and response use the same descriptor structure - */ -struct i40e_aqc_set_get_storm_control_config { - __le32 broadcast_threshold; - __le32 multicast_threshold; - __le32 control_flags; -#define I40E_AQC_STORM_CONTROL_MDIPW 0x01 -#define I40E_AQC_STORM_CONTROL_MDICW 0x02 -#define I40E_AQC_STORM_CONTROL_BDIPW 0x04 -#define I40E_AQC_STORM_CONTROL_BDICW 0x08 -#define I40E_AQC_STORM_CONTROL_BIDU 0x10 -#define I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT 8 -#define I40E_AQC_STORM_CONTROL_INTERVAL_MASK (0x3FF << \ - I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT) - u8 reserved[4]; -}; - -I40E_CHECK_CMD_LENGTH(i40e_aqc_set_get_storm_control_config); - /* DCB 0x03xx*/ /* PFC Ignore (direct 0x0301) @@ -1499,6 +1476,15 @@ struct i40e_aqc_query_switching_comp_bw_config_resp { * (direct 0x041B and 0x041C) uses the generic SEID struct */ +/* Configure partition BW + * (indirect 0x041D) + */ +struct i40e_aqc_configure_partition_bw_data { + __le16 pf_valid_bits; + u8 min_bw[16]; /* guaranteed bandwidth */ + u8 max_bw[16]; /* bandwidth limit */ +}; + /* Get and set the active HMC resource profile and status. * (direct 0x0500) and (direct 0x0501) */ @@ -1583,11 +1569,8 @@ struct i40e_aq_get_phy_abilities_resp { #define I40E_AQ_PHY_FLAG_PAUSE_TX 0x01 #define I40E_AQ_PHY_FLAG_PAUSE_RX 0x02 #define I40E_AQ_PHY_FLAG_LOW_POWER 0x04 -#define I40E_AQ_PHY_FLAG_AN_SHIFT 3 -#define I40E_AQ_PHY_FLAG_AN_MASK (0x3 << I40E_AQ_PHY_FLAG_AN_SHIFT) -#define I40E_AQ_PHY_FLAG_AN_OFF 0x00 /* link forced on */ -#define I40E_AQ_PHY_FLAG_AN_OFF_LINK_DOWN 0x01 -#define I40E_AQ_PHY_FLAG_AN_ON 0x02 +#define I40E_AQ_PHY_LINK_ENABLED 0x08 +#define I40E_AQ_PHY_AN_ENABLED 0x10 #define I40E_AQ_PHY_FLAG_MODULE_QUAL 0x20 __le16 eee_capability; #define I40E_AQ_EEE_100BASE_TX 0x0002 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h index 17e42ca26d0b..775fcb2463d7 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_lan_hmc.h @@ -53,6 +53,7 @@ struct i40e_hmc_obj_rxq { u8 tphdata_ena; u8 tphhead_ena; u8 lrxqthresh; + u8 prefena; /* NOTE: normally must be set to 1 at init */ }; /* Tx queue context data */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 2797548fde0d..da6054cbd9c0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -31,7 +31,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710 X710 Virtual Function Network Driver"; -#define DRV_VERSION "0.9.16" +#define DRV_VERSION "0.9.21" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; |