net: hns3: add support to modify tqps number

This patch adds the support to change tqps number for PF driver
by using ehtool -L command.

Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Mingguang Qu <qumingguang@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Peng Li 2017-12-22 12:21:41 +08:00 committed by David S. Miller
parent 482d2e9c1c
commit 09f2af6405
5 changed files with 240 additions and 0 deletions

View File

@ -388,6 +388,9 @@ struct hnae3_ae_ops {
enum hnae3_reset_type reset);
void (*get_channels)(struct hnae3_handle *handle,
struct ethtool_channels *ch);
void (*get_tqps_and_rss_info)(struct hnae3_handle *h,
u16 *free_tqps, u16 *max_rss_size);
int (*set_channels)(struct hnae3_handle *handle, u32 new_tqps_num);
};
struct hnae3_dcb_ops {

View File

@ -2651,6 +2651,19 @@ static int hns3_get_ring_config(struct hns3_nic_priv *priv)
return ret;
}
static void hns3_put_ring_config(struct hns3_nic_priv *priv)
{
struct hnae3_handle *h = priv->ae_handle;
int i;
for (i = 0; i < h->kinfo.num_tqps; i++) {
devm_kfree(priv->dev, priv->ring_data[i].ring);
devm_kfree(priv->dev,
priv->ring_data[i + h->kinfo.num_tqps].ring);
}
devm_kfree(priv->dev, priv->ring_data);
}
static int hns3_alloc_ring_memory(struct hns3_enet_ring *ring)
{
int ret;
@ -3162,6 +3175,115 @@ static int hns3_reset_notify(struct hnae3_handle *handle,
return ret;
}
static u16 hns3_get_max_available_channels(struct net_device *netdev)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
u16 free_tqps, max_rss_size, max_tqps;
h->ae_algo->ops->get_tqps_and_rss_info(h, &free_tqps, &max_rss_size);
max_tqps = h->kinfo.num_tc * max_rss_size;
return min_t(u16, max_tqps, (free_tqps + h->kinfo.num_tqps));
}
static int hns3_modify_tqp_num(struct net_device *netdev, u16 new_tqp_num)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = hns3_get_handle(netdev);
int ret;
ret = h->ae_algo->ops->set_channels(h, new_tqp_num);
if (ret)
return ret;
ret = hns3_get_ring_config(priv);
if (ret)
return ret;
ret = hns3_nic_init_vector_data(priv);
if (ret)
goto err_uninit_vector;
ret = hns3_init_all_ring(priv);
if (ret)
goto err_put_ring;
return 0;
err_put_ring:
hns3_put_ring_config(priv);
err_uninit_vector:
hns3_nic_uninit_vector_data(priv);
return ret;
}
static int hns3_adjust_tqps_num(u8 num_tc, u32 new_tqp_num)
{
return (new_tqp_num / num_tc) * num_tc;
}
int hns3_set_channels(struct net_device *netdev,
struct ethtool_channels *ch)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
struct hnae3_handle *h = hns3_get_handle(netdev);
struct hnae3_knic_private_info *kinfo = &h->kinfo;
bool if_running = netif_running(netdev);
u32 new_tqp_num = ch->combined_count;
u16 org_tqp_num;
int ret;
if (ch->rx_count || ch->tx_count)
return -EINVAL;
if (new_tqp_num > hns3_get_max_available_channels(netdev) ||
new_tqp_num < kinfo->num_tc) {
dev_err(&netdev->dev,
"Change tqps fail, the tqp range is from %d to %d",
kinfo->num_tc,
hns3_get_max_available_channels(netdev));
return -EINVAL;
}
new_tqp_num = hns3_adjust_tqps_num(kinfo->num_tc, new_tqp_num);
if (kinfo->num_tqps == new_tqp_num)
return 0;
if (if_running)
dev_close(netdev);
hns3_clear_all_ring(h);
ret = hns3_nic_uninit_vector_data(priv);
if (ret) {
dev_err(&netdev->dev,
"Unbind vector with tqp fail, nothing is changed");
goto open_netdev;
}
hns3_uninit_all_ring(priv);
org_tqp_num = h->kinfo.num_tqps;
ret = hns3_modify_tqp_num(netdev, new_tqp_num);
if (ret) {
ret = hns3_modify_tqp_num(netdev, org_tqp_num);
if (ret) {
/* If revert to old tqp failed, fatal error occurred */
dev_err(&netdev->dev,
"Revert to old tqp num fail, ret=%d", ret);
return ret;
}
dev_info(&netdev->dev,
"Change tqp num fail, Revert to old tqp num");
}
open_netdev:
if (if_running)
dev_open(netdev);
return ret;
}
static const struct hnae3_client_ops client_ops = {
.init_instance = hns3_client_init,
.uninit_instance = hns3_client_uninit,

View File

@ -595,6 +595,8 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value)
(((struct hns3_nic_priv *)netdev_priv(ndev))->ae_handle)
void hns3_ethtool_set_ops(struct net_device *netdev);
int hns3_set_channels(struct net_device *netdev,
struct ethtool_channels *ch);
bool hns3_clean_tx_ring(struct hns3_enet_ring *ring, int budget);
int hns3_init_all_ring(struct hns3_nic_priv *priv);

View File

@ -893,6 +893,7 @@ static const struct ethtool_ops hns3_ethtool_ops = {
.set_link_ksettings = hns3_set_link_ksettings,
.nway_reset = hns3_nway_reset,
.get_channels = hns3_get_channels,
.set_channels = hns3_set_channels,
};
void hns3_ethtool_set_ops(struct net_device *netdev)

View File

@ -5022,6 +5022,116 @@ static void hclge_get_channels(struct hnae3_handle *handle,
ch->combined_count = vport->alloc_tqps;
}
static void hclge_get_tqps_and_rss_info(struct hnae3_handle *handle,
u16 *free_tqps, u16 *max_rss_size)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
u16 temp_tqps = 0;
int i;
for (i = 0; i < hdev->num_tqps; i++) {
if (!hdev->htqp[i].alloced)
temp_tqps++;
}
*free_tqps = temp_tqps;
*max_rss_size = hdev->rss_size_max;
}
static void hclge_release_tqp(struct hclge_vport *vport)
{
struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
struct hclge_dev *hdev = vport->back;
int i;
for (i = 0; i < kinfo->num_tqps; i++) {
struct hclge_tqp *tqp =
container_of(kinfo->tqp[i], struct hclge_tqp, q);
tqp->q.handle = NULL;
tqp->q.tqp_index = 0;
tqp->alloced = false;
}
devm_kfree(&hdev->pdev->dev, kinfo->tqp);
kinfo->tqp = NULL;
}
static int hclge_set_channels(struct hnae3_handle *handle, u32 new_tqps_num)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hnae3_knic_private_info *kinfo = &vport->nic.kinfo;
struct hclge_dev *hdev = vport->back;
int cur_rss_size = kinfo->rss_size;
int cur_tqps = kinfo->num_tqps;
u16 tc_offset[HCLGE_MAX_TC_NUM];
u16 tc_valid[HCLGE_MAX_TC_NUM];
u16 tc_size[HCLGE_MAX_TC_NUM];
u16 roundup_size;
u32 *rss_indir;
int ret, i;
hclge_release_tqp(vport);
ret = hclge_knic_setup(vport, new_tqps_num);
if (ret) {
dev_err(&hdev->pdev->dev, "setup nic fail, ret =%d\n", ret);
return ret;
}
ret = hclge_map_tqp_to_vport(hdev, vport);
if (ret) {
dev_err(&hdev->pdev->dev, "map vport tqp fail, ret =%d\n", ret);
return ret;
}
ret = hclge_tm_schd_init(hdev);
if (ret) {
dev_err(&hdev->pdev->dev, "tm schd init fail, ret =%d\n", ret);
return ret;
}
roundup_size = roundup_pow_of_two(kinfo->rss_size);
roundup_size = ilog2(roundup_size);
/* Set the RSS TC mode according to the new RSS size */
for (i = 0; i < HCLGE_MAX_TC_NUM; i++) {
tc_valid[i] = 0;
if (!(hdev->hw_tc_map & BIT(i)))
continue;
tc_valid[i] = 1;
tc_size[i] = roundup_size;
tc_offset[i] = kinfo->rss_size * i;
}
ret = hclge_set_rss_tc_mode(hdev, tc_valid, tc_size, tc_offset);
if (ret)
return ret;
/* Reinitializes the rss indirect table according to the new RSS size */
rss_indir = kcalloc(HCLGE_RSS_IND_TBL_SIZE, sizeof(u32), GFP_KERNEL);
if (!rss_indir)
return -ENOMEM;
for (i = 0; i < HCLGE_RSS_IND_TBL_SIZE; i++)
rss_indir[i] = i % kinfo->rss_size;
ret = hclge_set_rss(handle, rss_indir, NULL, 0);
if (ret)
dev_err(&hdev->pdev->dev, "set rss indir table fail, ret=%d\n",
ret);
kfree(rss_indir);
if (!ret)
dev_info(&hdev->pdev->dev,
"Channels changed, rss_size from %d to %d, tqps from %d to %d",
cur_rss_size, kinfo->rss_size,
cur_tqps, kinfo->rss_size * kinfo->num_tc);
return ret;
}
static const struct hnae3_ae_ops hclge_ops = {
.init_ae_dev = hclge_init_ae_dev,
.uninit_ae_dev = hclge_uninit_ae_dev,
@ -5066,6 +5176,8 @@ static const struct hnae3_ae_ops hclge_ops = {
.set_vlan_filter = hclge_set_port_vlan_filter,
.set_vf_vlan_filter = hclge_set_vf_vlan_filter,
.reset_event = hclge_reset_event,
.get_tqps_and_rss_info = hclge_get_tqps_and_rss_info,
.set_channels = hclge_set_channels,
.get_channels = hclge_get_channels,
};