net: hns3: add support for set_rxnfc

This patch supports the ethtool's set_rxnfc().

Signed-off-by: Lipeng <lipeng321@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Lipeng 2017-10-10 16:42:05 +08:00 committed by David S. Miller
parent 5668abda09
commit f7db940afc
6 changed files with 129 additions and 2 deletions

View file

@ -339,6 +339,8 @@ struct hnae3_ae_ops {
u8 *hfunc);
int (*set_rss)(struct hnae3_handle *handle, const u32 *indir,
const u8 *key, const u8 hfunc);
int (*set_rss_tuple)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int (*get_tc_size)(struct hnae3_handle *handle);

View file

@ -85,6 +85,15 @@ static int hclge_init_cmd_queue(struct hclge_dev *hdev, int ring_type)
return 0;
}
void hclge_cmd_reuse_desc(struct hclge_desc *desc, bool is_read)
{
desc->flag = cpu_to_le16(HCLGE_CMD_FLAG_NO_INTR | HCLGE_CMD_FLAG_IN);
if (is_read)
desc->flag |= cpu_to_le16(HCLGE_CMD_FLAG_WR);
else
desc->flag &= cpu_to_le16(~HCLGE_CMD_FLAG_WR);
}
void hclge_cmd_setup_basic_desc(struct hclge_desc *desc,
enum hclge_opcode_type opcode, bool is_read)
{

View file

@ -739,6 +739,7 @@ struct hclge_hw;
int hclge_cmd_send(struct hclge_hw *hw, struct hclge_desc *desc, int num);
void hclge_cmd_setup_basic_desc(struct hclge_desc *desc,
enum hclge_opcode_type opcode, bool is_read);
void hclge_cmd_reuse_desc(struct hclge_desc *desc, bool is_read);
int hclge_cmd_set_promisc_mode(struct hclge_dev *hdev,
struct hclge_promisc_param *param);

View file

@ -2595,8 +2595,6 @@ static int hclge_set_rss_tc_mode(struct hclge_dev *hdev, u16 *tc_valid,
static int hclge_set_rss_input_tuple(struct hclge_dev *hdev)
{
#define HCLGE_RSS_INPUT_TUPLE_OTHER 0xf
#define HCLGE_RSS_INPUT_TUPLE_SCTP 0x1f
struct hclge_rss_input_tuple_cmd *req;
struct hclge_desc desc;
int ret;
@ -2677,6 +2675,98 @@ static int hclge_set_rss(struct hnae3_handle *handle, const u32 *indir,
return ret;
}
static u8 hclge_get_rss_hash_bits(struct ethtool_rxnfc *nfc)
{
u8 hash_sets = nfc->data & RXH_L4_B_0_1 ? HCLGE_S_PORT_BIT : 0;
if (nfc->data & RXH_L4_B_2_3)
hash_sets |= HCLGE_D_PORT_BIT;
else
hash_sets &= ~HCLGE_D_PORT_BIT;
if (nfc->data & RXH_IP_SRC)
hash_sets |= HCLGE_S_IP_BIT;
else
hash_sets &= ~HCLGE_S_IP_BIT;
if (nfc->data & RXH_IP_DST)
hash_sets |= HCLGE_D_IP_BIT;
else
hash_sets &= ~HCLGE_D_IP_BIT;
if (nfc->flow_type == SCTP_V4_FLOW || nfc->flow_type == SCTP_V6_FLOW)
hash_sets |= HCLGE_V_TAG_BIT;
return hash_sets;
}
static int hclge_set_rss_tuple(struct hnae3_handle *handle,
struct ethtool_rxnfc *nfc)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
struct hclge_rss_input_tuple_cmd *req;
struct hclge_desc desc;
u8 tuple_sets;
int ret;
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3))
return -EINVAL;
req = (struct hclge_rss_input_tuple_cmd *)desc.data;
hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_RSS_INPUT_TUPLE, true);
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret) {
dev_err(&hdev->pdev->dev,
"Read rss tuple fail, status = %d\n", ret);
return ret;
}
hclge_cmd_reuse_desc(&desc, false);
tuple_sets = hclge_get_rss_hash_bits(nfc);
switch (nfc->flow_type) {
case TCP_V4_FLOW:
req->ipv4_tcp_en = tuple_sets;
break;
case TCP_V6_FLOW:
req->ipv6_tcp_en = tuple_sets;
break;
case UDP_V4_FLOW:
req->ipv4_udp_en = tuple_sets;
break;
case UDP_V6_FLOW:
req->ipv6_udp_en = tuple_sets;
break;
case SCTP_V4_FLOW:
req->ipv4_sctp_en = tuple_sets;
break;
case SCTP_V6_FLOW:
if ((nfc->data & RXH_L4_B_0_1) ||
(nfc->data & RXH_L4_B_2_3))
return -EINVAL;
req->ipv6_sctp_en = tuple_sets;
break;
case IPV4_FLOW:
req->ipv4_fragment_en = HCLGE_RSS_INPUT_TUPLE_OTHER;
break;
case IPV6_FLOW:
req->ipv6_fragment_en = HCLGE_RSS_INPUT_TUPLE_OTHER;
break;
default:
return -EINVAL;
}
ret = hclge_cmd_send(&hdev->hw, &desc, 1);
if (ret)
dev_err(&hdev->pdev->dev,
"Set rss tuple fail, status = %d\n", ret);
return ret;
}
static int hclge_get_tc_size(struct hnae3_handle *handle)
{
struct hclge_vport *vport = hclge_get_vport(handle);
@ -4344,6 +4434,7 @@ static const struct hnae3_ae_ops hclge_ops = {
.get_rss_indir_size = hclge_get_rss_indir_size,
.get_rss = hclge_get_rss,
.set_rss = hclge_set_rss,
.set_rss_tuple = hclge_set_rss_tuple,
.get_tc_size = hclge_get_tc_size,
.get_mac_addr = hclge_get_mac_addr,
.set_mac_addr = hclge_set_mac_addr,

View file

@ -41,6 +41,14 @@
#define HCLGE_RSS_CFG_TBL_NUM \
(HCLGE_RSS_IND_TBL_SIZE / HCLGE_RSS_CFG_TBL_SIZE)
#define HCLGE_RSS_INPUT_TUPLE_OTHER GENMASK(3, 0)
#define HCLGE_RSS_INPUT_TUPLE_SCTP GENMASK(4, 0)
#define HCLGE_D_PORT_BIT BIT(0)
#define HCLGE_S_PORT_BIT BIT(1)
#define HCLGE_D_IP_BIT BIT(2)
#define HCLGE_S_IP_BIT BIT(3)
#define HCLGE_V_TAG_BIT BIT(4)
#define HCLGE_RSS_TC_SIZE_0 1
#define HCLGE_RSS_TC_SIZE_1 2
#define HCLGE_RSS_TC_SIZE_2 4

View file

@ -533,6 +533,21 @@ int hns3_set_ringparam(struct net_device *ndev, struct ethtool_ringparam *param)
return ret;
}
static int hns3_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->set_rss_tuple)
return -EOPNOTSUPP;
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
return h->ae_algo->ops->set_rss_tuple(h, cmd);
default:
return -EOPNOTSUPP;
}
}
static const struct ethtool_ops hns3_ethtool_ops = {
.get_drvinfo = hns3_get_drvinfo,
.get_link = hns3_get_link,
@ -543,6 +558,7 @@ static const struct ethtool_ops hns3_ethtool_ops = {
.get_ethtool_stats = hns3_get_stats,
.get_sset_count = hns3_get_sset_count,
.get_rxnfc = hns3_get_rxnfc,
.set_rxnfc = hns3_set_rxnfc,
.get_rxfh_key_size = hns3_get_rss_key_size,
.get_rxfh_indir_size = hns3_get_rss_indir_size,
.get_rxfh = hns3_get_rss,