diff options
Diffstat (limited to 'drivers/net/vmxnet3/vmxnet3_ethtool.c')
-rw-r--r-- | drivers/net/vmxnet3/vmxnet3_ethtool.c | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c index 38f7c7975e1f..aabc6ef366b4 100644 --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c @@ -725,6 +725,162 @@ vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key, } #endif +static int +vmxnet3_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) +{ + struct vmxnet3_adapter *adapter = netdev_priv(netdev); + + if (!VMXNET3_VERSION_GE_3(adapter)) + return -EOPNOTSUPP; + + switch (adapter->coal_conf->coalMode) { + case VMXNET3_COALESCE_DISABLED: + /* struct ethtool_coalesce is already initialized to 0 */ + break; + case VMXNET3_COALESCE_ADAPT: + ec->use_adaptive_rx_coalesce = true; + break; + case VMXNET3_COALESCE_STATIC: + ec->tx_max_coalesced_frames = + adapter->coal_conf->coalPara.coalStatic.tx_comp_depth; + ec->rx_max_coalesced_frames = + adapter->coal_conf->coalPara.coalStatic.rx_depth; + break; + case VMXNET3_COALESCE_RBC: { + u32 rbc_rate; + + rbc_rate = adapter->coal_conf->coalPara.coalRbc.rbc_rate; + ec->rx_coalesce_usecs = VMXNET3_COAL_RBC_USECS(rbc_rate); + } + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int +vmxnet3_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) +{ + struct vmxnet3_adapter *adapter = netdev_priv(netdev); + struct Vmxnet3_DriverShared *shared = adapter->shared; + union Vmxnet3_CmdInfo *cmdInfo = &shared->cu.cmdInfo; + unsigned long flags; + + if (!VMXNET3_VERSION_GE_3(adapter)) + return -EOPNOTSUPP; + + if (ec->rx_coalesce_usecs_irq || + ec->rx_max_coalesced_frames_irq || + ec->tx_coalesce_usecs || + ec->tx_coalesce_usecs_irq || + ec->tx_max_coalesced_frames_irq || + ec->stats_block_coalesce_usecs || + ec->use_adaptive_tx_coalesce || + ec->pkt_rate_low || + ec->rx_coalesce_usecs_low || + ec->rx_max_coalesced_frames_low || + ec->tx_coalesce_usecs_low || + ec->tx_max_coalesced_frames_low || + ec->pkt_rate_high || + ec->rx_coalesce_usecs_high || + ec->rx_max_coalesced_frames_high || + ec->tx_coalesce_usecs_high || + ec->tx_max_coalesced_frames_high || + ec->rate_sample_interval) { + return -EINVAL; + } + + if ((ec->rx_coalesce_usecs == 0) && + (ec->use_adaptive_rx_coalesce == 0) && + (ec->tx_max_coalesced_frames == 0) && + (ec->rx_max_coalesced_frames == 0)) { + memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf)); + adapter->coal_conf->coalMode = VMXNET3_COALESCE_DISABLED; + goto done; + } + + if (ec->rx_coalesce_usecs != 0) { + u32 rbc_rate; + + if ((ec->use_adaptive_rx_coalesce != 0) || + (ec->tx_max_coalesced_frames != 0) || + (ec->rx_max_coalesced_frames != 0)) { + return -EINVAL; + } + + rbc_rate = VMXNET3_COAL_RBC_RATE(ec->rx_coalesce_usecs); + if (rbc_rate < VMXNET3_COAL_RBC_MIN_RATE || + rbc_rate > VMXNET3_COAL_RBC_MAX_RATE) { + return -EINVAL; + } + + memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf)); + adapter->coal_conf->coalMode = VMXNET3_COALESCE_RBC; + adapter->coal_conf->coalPara.coalRbc.rbc_rate = rbc_rate; + goto done; + } + + if (ec->use_adaptive_rx_coalesce != 0) { + if ((ec->rx_coalesce_usecs != 0) || + (ec->tx_max_coalesced_frames != 0) || + (ec->rx_max_coalesced_frames != 0)) { + return -EINVAL; + } + memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf)); + adapter->coal_conf->coalMode = VMXNET3_COALESCE_ADAPT; + goto done; + } + + if ((ec->tx_max_coalesced_frames != 0) || + (ec->rx_max_coalesced_frames != 0)) { + if ((ec->rx_coalesce_usecs != 0) || + (ec->use_adaptive_rx_coalesce != 0)) { + return -EINVAL; + } + + if ((ec->tx_max_coalesced_frames > + VMXNET3_COAL_STATIC_MAX_DEPTH) || + (ec->rx_max_coalesced_frames > + VMXNET3_COAL_STATIC_MAX_DEPTH)) { + return -EINVAL; + } + + memset(adapter->coal_conf, 0, sizeof(*adapter->coal_conf)); + adapter->coal_conf->coalMode = VMXNET3_COALESCE_STATIC; + + adapter->coal_conf->coalPara.coalStatic.tx_comp_depth = + (ec->tx_max_coalesced_frames ? + ec->tx_max_coalesced_frames : + VMXNET3_COAL_STATIC_DEFAULT_DEPTH); + + adapter->coal_conf->coalPara.coalStatic.rx_depth = + (ec->rx_max_coalesced_frames ? + ec->rx_max_coalesced_frames : + VMXNET3_COAL_STATIC_DEFAULT_DEPTH); + + adapter->coal_conf->coalPara.coalStatic.tx_depth = + VMXNET3_COAL_STATIC_DEFAULT_DEPTH; + goto done; + } + +done: + adapter->default_coal_mode = false; + if (netif_running(netdev)) { + spin_lock_irqsave(&adapter->cmd_lock, flags); + cmdInfo->varConf.confVer = 1; + cmdInfo->varConf.confLen = + cpu_to_le32(sizeof(*adapter->coal_conf)); + cmdInfo->varConf.confPA = cpu_to_le64(adapter->coal_conf_pa); + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, + VMXNET3_CMD_SET_COALESCE); + spin_unlock_irqrestore(&adapter->cmd_lock, flags); + } + + return 0; +} + static const struct ethtool_ops vmxnet3_ethtool_ops = { .get_settings = vmxnet3_get_settings, .get_drvinfo = vmxnet3_get_drvinfo, @@ -733,6 +889,8 @@ static const struct ethtool_ops vmxnet3_ethtool_ops = { .get_wol = vmxnet3_get_wol, .set_wol = vmxnet3_set_wol, .get_link = ethtool_op_get_link, + .get_coalesce = vmxnet3_get_coalesce, + .set_coalesce = vmxnet3_set_coalesce, .get_strings = vmxnet3_get_strings, .get_sset_count = vmxnet3_get_sset_count, .get_ethtool_stats = vmxnet3_get_ethtool_stats, |