Commit 01b5277f authored by Tom Lendacky's avatar Tom Lendacky Committed by David S. Miller

amd-xgbe: Add ethtool show/set channels support

Add ethtool support to show and set the device channel configuration.
Changing the channel configuration will result in a device restart.
Signed-off-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 22447534
...@@ -1329,6 +1329,17 @@ static int xgbe_alloc_memory(struct xgbe_prv_data *pdata) ...@@ -1329,6 +1329,17 @@ static int xgbe_alloc_memory(struct xgbe_prv_data *pdata)
struct net_device *netdev = pdata->netdev; struct net_device *netdev = pdata->netdev;
int ret; int ret;
if (pdata->new_tx_ring_count) {
pdata->tx_ring_count = pdata->new_tx_ring_count;
pdata->tx_q_count = pdata->tx_ring_count;
pdata->new_tx_ring_count = 0;
}
if (pdata->new_rx_ring_count) {
pdata->rx_ring_count = pdata->new_rx_ring_count;
pdata->new_rx_ring_count = 0;
}
/* Calculate the Rx buffer size before allocating rings */ /* Calculate the Rx buffer size before allocating rings */
pdata->rx_buf_size = xgbe_calc_rx_buf_size(netdev, netdev->mtu); pdata->rx_buf_size = xgbe_calc_rx_buf_size(netdev, netdev->mtu);
...@@ -1482,6 +1493,20 @@ static void xgbe_stopdev(struct work_struct *work) ...@@ -1482,6 +1493,20 @@ static void xgbe_stopdev(struct work_struct *work)
netdev_alert(pdata->netdev, "device stopped\n"); netdev_alert(pdata->netdev, "device stopped\n");
} }
void xgbe_full_restart_dev(struct xgbe_prv_data *pdata)
{
/* If not running, "restart" will happen on open */
if (!netif_running(pdata->netdev))
return;
xgbe_stop(pdata);
xgbe_free_memory(pdata);
xgbe_alloc_memory(pdata);
xgbe_start(pdata);
}
void xgbe_restart_dev(struct xgbe_prv_data *pdata) void xgbe_restart_dev(struct xgbe_prv_data *pdata)
{ {
/* If not running, "restart" will happen on open */ /* If not running, "restart" will happen on open */
......
...@@ -705,6 +705,138 @@ static int xgbe_set_ringparam(struct net_device *netdev, ...@@ -705,6 +705,138 @@ static int xgbe_set_ringparam(struct net_device *netdev,
return 0; return 0;
} }
static void xgbe_get_channels(struct net_device *netdev,
struct ethtool_channels *channels)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
unsigned int rx, tx, combined;
/* Calculate maximums allowed:
* - Take into account the number of available IRQs
* - Do not take into account the number of online CPUs so that
* the user can over-subscribe if desired
* - Tx is additionally limited by the number of hardware queues
*/
rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count);
rx = min(rx, pdata->channel_irq_count);
tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count);
tx = min(tx, pdata->channel_irq_count);
tx = min(tx, pdata->tx_max_q_count);
combined = min(rx, tx);
channels->max_combined = combined;
channels->max_rx = rx ? rx - 1 : 0;
channels->max_tx = tx ? tx - 1 : 0;
/* Get current settings based on device state */
rx = pdata->new_rx_ring_count ? : pdata->rx_ring_count;
tx = pdata->new_tx_ring_count ? : pdata->tx_ring_count;
combined = min(rx, tx);
rx -= combined;
tx -= combined;
channels->combined_count = combined;
channels->rx_count = rx;
channels->tx_count = tx;
}
static void xgbe_print_set_channels_input(struct net_device *netdev,
struct ethtool_channels *channels)
{
netdev_err(netdev, "channel inputs: combined=%u, rx-only=%u, tx-only=%u\n",
channels->combined_count, channels->rx_count,
channels->tx_count);
}
static int xgbe_set_channels(struct net_device *netdev,
struct ethtool_channels *channels)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
unsigned int rx, rx_curr, tx, tx_curr, combined;
/* Calculate maximums allowed:
* - Take into account the number of available IRQs
* - Do not take into account the number of online CPUs so that
* the user can over-subscribe if desired
* - Tx is additionally limited by the number of hardware queues
*/
rx = min(pdata->hw_feat.rx_ch_cnt, pdata->rx_max_channel_count);
rx = min(rx, pdata->channel_irq_count);
tx = min(pdata->hw_feat.tx_ch_cnt, pdata->tx_max_channel_count);
tx = min(tx, pdata->tx_max_q_count);
tx = min(tx, pdata->channel_irq_count);
combined = min(rx, tx);
/* Should not be setting other count */
if (channels->other_count) {
netdev_err(netdev,
"other channel count must be zero\n");
return -EINVAL;
}
/* Require at least one Combined (Rx and Tx) channel */
if (!channels->combined_count) {
netdev_err(netdev,
"at least one combined Rx/Tx channel is required\n");
xgbe_print_set_channels_input(netdev, channels);
return -EINVAL;
}
/* Check combined channels */
if (channels->combined_count > combined) {
netdev_err(netdev,
"combined channel count cannot exceed %u\n",
combined);
xgbe_print_set_channels_input(netdev, channels);
return -EINVAL;
}
/* Can have some Rx-only or Tx-only channels, but not both */
if (channels->rx_count && channels->tx_count) {
netdev_err(netdev,
"cannot specify both Rx-only and Tx-only channels\n");
xgbe_print_set_channels_input(netdev, channels);
return -EINVAL;
}
/* Check that we don't exceed the maximum number of channels */
if ((channels->combined_count + channels->rx_count) > rx) {
netdev_err(netdev,
"total Rx channels (%u) requested exceeds maximum available (%u)\n",
channels->combined_count + channels->rx_count, rx);
xgbe_print_set_channels_input(netdev, channels);
return -EINVAL;
}
if ((channels->combined_count + channels->tx_count) > tx) {
netdev_err(netdev,
"total Tx channels (%u) requested exceeds maximum available (%u)\n",
channels->combined_count + channels->tx_count, tx);
xgbe_print_set_channels_input(netdev, channels);
return -EINVAL;
}
rx = channels->combined_count + channels->rx_count;
tx = channels->combined_count + channels->tx_count;
rx_curr = pdata->new_rx_ring_count ? : pdata->rx_ring_count;
tx_curr = pdata->new_tx_ring_count ? : pdata->tx_ring_count;
if ((rx == rx_curr) && (tx == tx_curr))
goto out;
pdata->new_rx_ring_count = rx;
pdata->new_tx_ring_count = tx;
xgbe_full_restart_dev(pdata);
out:
return 0;
}
static const struct ethtool_ops xgbe_ethtool_ops = { static const struct ethtool_ops xgbe_ethtool_ops = {
.get_drvinfo = xgbe_get_drvinfo, .get_drvinfo = xgbe_get_drvinfo,
.get_msglevel = xgbe_get_msglevel, .get_msglevel = xgbe_get_msglevel,
...@@ -729,6 +861,8 @@ static const struct ethtool_ops xgbe_ethtool_ops = { ...@@ -729,6 +861,8 @@ static const struct ethtool_ops xgbe_ethtool_ops = {
.get_module_eeprom = xgbe_get_module_eeprom, .get_module_eeprom = xgbe_get_module_eeprom,
.get_ringparam = xgbe_get_ringparam, .get_ringparam = xgbe_get_ringparam,
.set_ringparam = xgbe_set_ringparam, .set_ringparam = xgbe_set_ringparam,
.get_channels = xgbe_get_channels,
.set_channels = xgbe_set_channels,
}; };
const struct ethtool_ops *xgbe_get_ethtool_ops(void) const struct ethtool_ops *xgbe_get_ethtool_ops(void)
......
...@@ -1122,6 +1122,9 @@ struct xgbe_prv_data { ...@@ -1122,6 +1122,9 @@ struct xgbe_prv_data {
unsigned int rx_ring_count; unsigned int rx_ring_count;
unsigned int rx_desc_count; unsigned int rx_desc_count;
unsigned int new_tx_ring_count;
unsigned int new_rx_ring_count;
unsigned int tx_max_q_count; unsigned int tx_max_q_count;
unsigned int rx_max_q_count; unsigned int rx_max_q_count;
unsigned int tx_q_count; unsigned int tx_q_count;
...@@ -1336,6 +1339,7 @@ int xgbe_powerdown(struct net_device *, unsigned int); ...@@ -1336,6 +1339,7 @@ int xgbe_powerdown(struct net_device *, unsigned int);
void xgbe_init_rx_coalesce(struct xgbe_prv_data *); void xgbe_init_rx_coalesce(struct xgbe_prv_data *);
void xgbe_init_tx_coalesce(struct xgbe_prv_data *); void xgbe_init_tx_coalesce(struct xgbe_prv_data *);
void xgbe_restart_dev(struct xgbe_prv_data *pdata); void xgbe_restart_dev(struct xgbe_prv_data *pdata);
void xgbe_full_restart_dev(struct xgbe_prv_data *pdata);
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
void xgbe_debugfs_init(struct xgbe_prv_data *); void xgbe_debugfs_init(struct xgbe_prv_data *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment