diff options
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_sriov.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_sriov.c | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c index 58c9b45989ff..6e50d8328942 100644 --- a/drivers/net/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ixgbe/ixgbe_sriov.c @@ -478,9 +478,90 @@ out: return err; } +static int ixgbe_link_mbps(int internal_link_speed) +{ + switch (internal_link_speed) { + case IXGBE_LINK_SPEED_100_FULL: + return 100; + case IXGBE_LINK_SPEED_1GB_FULL: + return 1000; + case IXGBE_LINK_SPEED_10GB_FULL: + return 10000; + default: + return 0; + } +} + +static void ixgbe_set_vf_rate_limit(struct ixgbe_hw *hw, int vf, int tx_rate, + int link_speed) +{ + int rf_dec, rf_int; + u32 bcnrc_val; + + if (tx_rate != 0) { + /* Calculate the rate factor values to set */ + rf_int = link_speed / tx_rate; + rf_dec = (link_speed - (rf_int * tx_rate)); + rf_dec = (rf_dec * (1<<IXGBE_RTTBCNRC_RF_INT_SHIFT)) / tx_rate; + + bcnrc_val = IXGBE_RTTBCNRC_RS_ENA; + bcnrc_val |= ((rf_int<<IXGBE_RTTBCNRC_RF_INT_SHIFT) & + IXGBE_RTTBCNRC_RF_INT_MASK); + bcnrc_val |= (rf_dec & IXGBE_RTTBCNRC_RF_DEC_MASK); + } else { + bcnrc_val = 0; + } + + IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, 2*vf); /* vf Y uses queue 2*Y */ + IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, bcnrc_val); +} + +void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter) +{ + int actual_link_speed, i; + bool reset_rate = false; + + /* VF Tx rate limit was not set */ + if (adapter->vf_rate_link_speed == 0) + return; + + actual_link_speed = ixgbe_link_mbps(adapter->link_speed); + if (actual_link_speed != adapter->vf_rate_link_speed) { + reset_rate = true; + adapter->vf_rate_link_speed = 0; + dev_info(&adapter->pdev->dev, + "Link speed has been changed. VF Transmit rate " + "is disabled\n"); + } + + for (i = 0; i < adapter->num_vfs; i++) { + if (reset_rate) + adapter->vfinfo[i].tx_rate = 0; + + ixgbe_set_vf_rate_limit(&adapter->hw, i, + adapter->vfinfo[i].tx_rate, + actual_link_speed); + } +} + int ixgbe_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate) { - return -EOPNOTSUPP; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + struct ixgbe_hw *hw = &adapter->hw; + int actual_link_speed; + + actual_link_speed = ixgbe_link_mbps(adapter->link_speed); + if ((vf >= adapter->num_vfs) || (!adapter->link_up) || + (tx_rate > actual_link_speed) || (actual_link_speed != 10000) || + ((tx_rate != 0) && (tx_rate <= 10))) + /* rate limit cannot be set to 10Mb or less in 10Gb adapters */ + return -EINVAL; + + adapter->vf_rate_link_speed = actual_link_speed; + adapter->vfinfo[vf].tx_rate = (u16)tx_rate; + ixgbe_set_vf_rate_limit(hw, vf, tx_rate, actual_link_speed); + + return 0; } int ixgbe_ndo_get_vf_config(struct net_device *netdev, @@ -491,7 +572,7 @@ int ixgbe_ndo_get_vf_config(struct net_device *netdev, return -EINVAL; ivi->vf = vf; memcpy(&ivi->mac, adapter->vfinfo[vf].vf_mac_addresses, ETH_ALEN); - ivi->tx_rate = 0; + ivi->tx_rate = adapter->vfinfo[vf].tx_rate; ivi->vlan = adapter->vfinfo[vf].pf_vlan; ivi->qos = adapter->vfinfo[vf].pf_qos; return 0; |