Commit 6140cc20 authored by David S. Miller's avatar David S. Miller

Merge branch 'Support-of-Flow-Director-in-HNS3-Ethernet-Driver-for-HiP08-Rev2-SoC'

Salil Mehta says:

====================
Support of Flow Director in HNS3 Ethernet Driver for HiP08 Rev2 SoC

This patch-set adds the support of FD(Flow Director) in the HNS3 PF driver
for HiP08 Rev2(0x21) SoC of Hisilicon. FD can be used in filtering the flows
and deciding to drop the flow or forward it to paricular queue.

Configuration consists of rules with input keys and actions. The rules are
stored in TCAM.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 26cf48a6 c17852a8
......@@ -51,6 +51,7 @@
#define HNAE3_KNIC_CLIENT_INITED_B 0x3
#define HNAE3_UNIC_CLIENT_INITED_B 0x4
#define HNAE3_ROCE_CLIENT_INITED_B 0x5
#define HNAE3_DEV_SUPPORT_FD_B 0x6
#define HNAE3_DEV_SUPPORT_ROCE_DCB_BITS (BIT(HNAE3_DEV_SUPPORT_DCB_B) |\
BIT(HNAE3_DEV_SUPPORT_ROCE_B))
......@@ -61,6 +62,9 @@
#define hnae3_dev_dcb_supported(hdev) \
hnae3_get_bit(hdev->ae_dev->flag, HNAE3_DEV_SUPPORT_DCB_B)
#define hnae3_dev_fd_supported(hdev) \
hnae3_get_bit((hdev)->ae_dev->flag, HNAE3_DEV_SUPPORT_FD_B)
#define ring_ptr_move_fw(ring, p) \
((ring)->p = ((ring)->p + 1) % (ring)->desc_num)
#define ring_ptr_move_bw(ring, p) \
......@@ -175,6 +179,7 @@ struct hnae3_ae_dev {
struct list_head node;
u32 flag;
enum hnae3_dev_type dev_type;
enum hnae3_reset_type reset_type;
void *priv;
};
......@@ -412,6 +417,20 @@ struct hnae3_ae_ops {
void (*get_link_mode)(struct hnae3_handle *handle,
unsigned long *supported,
unsigned long *advertising);
int (*add_fd_entry)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int (*del_fd_entry)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
void (*del_all_fd_entries)(struct hnae3_handle *handle,
bool clear_list);
int (*get_fd_rule_cnt)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int (*get_fd_rule_info)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd);
int (*get_fd_all_rules)(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd, u32 *rule_locs);
int (*restore_fd_rules)(struct hnae3_handle *handle);
void (*enable_fd)(struct hnae3_handle *handle, bool enable);
};
struct hnae3_dcb_ops {
......
......@@ -1285,6 +1285,13 @@ static int hns3_nic_set_features(struct net_device *netdev,
return ret;
}
if ((changed & NETIF_F_NTUPLE) && h->ae_algo->ops->enable_fd) {
if (features & NETIF_F_NTUPLE)
h->ae_algo->ops->enable_fd(h, true);
else
h->ae_algo->ops->enable_fd(h, false);
}
netdev->features = features;
return 0;
}
......@@ -1622,6 +1629,13 @@ static void hns3_disable_sriov(struct pci_dev *pdev)
pci_disable_sriov(pdev);
}
static void hns3_get_dev_capability(struct pci_dev *pdev,
struct hnae3_ae_dev *ae_dev)
{
if (pdev->revision >= 0x21)
hnae3_set_bit(ae_dev->flag, HNAE3_DEV_SUPPORT_FD_B, 1);
}
/* hns3_probe - Device initialization routine
* @pdev: PCI device information struct
* @ent: entry in hns3_pci_tbl
......@@ -1647,6 +1661,8 @@ static int hns3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ae_dev->pdev = pdev;
ae_dev->flag = ent->driver_data;
ae_dev->dev_type = HNAE3_DEV_KNIC;
ae_dev->reset_type = HNAE3_NONE_RESET;
hns3_get_dev_capability(pdev, ae_dev);
pci_set_drvdata(pdev, ae_dev);
hnae3_register_ae_dev(ae_dev);
......@@ -1761,8 +1777,14 @@ static void hns3_set_default_feature(struct net_device *netdev)
NETIF_F_GSO_GRE_CSUM | NETIF_F_GSO_UDP_TUNNEL |
NETIF_F_GSO_UDP_TUNNEL_CSUM | NETIF_F_SCTP_CRC;
if (pdev->revision != 0x20)
if (pdev->revision >= 0x21) {
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
if (!(h->flags & HNAE3_SUPPORT_VF)) {
netdev->hw_features |= NETIF_F_NTUPLE;
netdev->features |= NETIF_F_NTUPLE;
}
}
}
static int hns3_alloc_buffer(struct hns3_enet_ring *ring,
......@@ -3142,6 +3164,25 @@ static void hns3_uninit_mac_addr(struct net_device *netdev)
h->ae_algo->ops->rm_uc_addr(h, netdev->dev_addr);
}
static int hns3_restore_fd_rules(struct net_device *netdev)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
int ret = 0;
if (h->ae_algo->ops->restore_fd_rules)
ret = h->ae_algo->ops->restore_fd_rules(h);
return ret;
}
static void hns3_del_all_fd_rules(struct net_device *netdev, bool clear_list)
{
struct hnae3_handle *h = hns3_get_handle(netdev);
if (h->ae_algo->ops->del_all_fd_entries)
h->ae_algo->ops->del_all_fd_entries(h, clear_list);
}
static void hns3_nic_set_priv_ops(struct net_device *netdev)
{
struct hns3_nic_priv *priv = netdev_priv(netdev);
......@@ -3258,6 +3299,8 @@ static void hns3_client_uninit(struct hnae3_handle *handle, bool reset)
if (netdev->reg_state != NETREG_UNINITIALIZED)
unregister_netdev(netdev);
hns3_del_all_fd_rules(netdev, true);
hns3_force_clear_all_rx_ring(handle);
ret = hns3_nic_uninit_vector_data(priv);
......@@ -3553,6 +3596,8 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
if (!(handle->flags & HNAE3_SUPPORT_VF))
hns3_restore_vlan(netdev);
hns3_restore_fd_rules(netdev);
/* Carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
......@@ -3573,6 +3618,7 @@ static int hns3_reset_notify_init_enet(struct hnae3_handle *handle)
static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
{
struct hnae3_ae_dev *ae_dev = pci_get_drvdata(handle->pdev);
struct net_device *netdev = handle->kinfo.netdev;
struct hns3_nic_priv *priv = netdev_priv(netdev);
int ret;
......@@ -3593,6 +3639,13 @@ static int hns3_reset_notify_uninit_enet(struct hnae3_handle *handle)
hns3_uninit_mac_addr(netdev);
/* it is cumbersome for hardware to pick-and-choose rules for deletion
* from TCAM. Hence, for function reset software intervention is
* required to delete the rules
*/
if (hns3_dev_ongoing_func_reset(ae_dev))
hns3_del_all_fd_rules(netdev, false);
return ret;
}
......
......@@ -585,6 +585,11 @@ static inline void hns3_write_reg(void __iomem *base, u32 reg, u32 value)
writel(value, reg_addr + reg);
}
static inline bool hns3_dev_ongoing_func_reset(struct hnae3_ae_dev *ae_dev)
{
return (ae_dev && (ae_dev->reset_type == HNAE3_FUNC_RESET));
}
#define hns3_write_dev(a, reg, value) \
hns3_write_reg((a)->io_base, (reg), (value))
......
......@@ -699,20 +699,33 @@ static int hns3_get_rxnfc(struct net_device *netdev,
{
struct hnae3_handle *h = hns3_get_handle(netdev);
if (!h->ae_algo || !h->ae_algo->ops || !h->ae_algo->ops->get_rss_tuple)
if (!h->ae_algo || !h->ae_algo->ops)
return -EOPNOTSUPP;
switch (cmd->cmd) {
case ETHTOOL_GRXRINGS:
cmd->data = h->kinfo.rss_size;
break;
cmd->data = h->kinfo.num_tqps;
return 0;
case ETHTOOL_GRXFH:
return h->ae_algo->ops->get_rss_tuple(h, cmd);
if (h->ae_algo->ops->get_rss_tuple)
return h->ae_algo->ops->get_rss_tuple(h, cmd);
return -EOPNOTSUPP;
case ETHTOOL_GRXCLSRLCNT:
if (h->ae_algo->ops->get_fd_rule_cnt)
return h->ae_algo->ops->get_fd_rule_cnt(h, cmd);
return -EOPNOTSUPP;
case ETHTOOL_GRXCLSRULE:
if (h->ae_algo->ops->get_fd_rule_info)
return h->ae_algo->ops->get_fd_rule_info(h, cmd);
return -EOPNOTSUPP;
case ETHTOOL_GRXCLSRLALL:
if (h->ae_algo->ops->get_fd_all_rules)
return h->ae_algo->ops->get_fd_all_rules(h, cmd,
rule_locs);
return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int hns3_change_all_ring_bd_num(struct hns3_nic_priv *priv,
......@@ -795,12 +808,22 @@ 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)
if (!h->ae_algo || !h->ae_algo->ops)
return -EOPNOTSUPP;
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
return h->ae_algo->ops->set_rss_tuple(h, cmd);
if (h->ae_algo->ops->set_rss_tuple)
return h->ae_algo->ops->set_rss_tuple(h, cmd);
return -EOPNOTSUPP;
case ETHTOOL_SRXCLSRLINS:
if (h->ae_algo->ops->add_fd_entry)
return h->ae_algo->ops->add_fd_entry(h, cmd);
return -EOPNOTSUPP;
case ETHTOOL_SRXCLSRLDEL:
if (h->ae_algo->ops->del_fd_entry)
return h->ae_algo->ops->del_fd_entry(h, cmd);
return -EOPNOTSUPP;
default:
return -EOPNOTSUPP;
}
......
......@@ -190,6 +190,13 @@ enum hclge_opcode_type {
HCLGE_OPC_VLAN_FILTER_PF_CFG = 0x1101,
HCLGE_OPC_VLAN_FILTER_VF_CFG = 0x1102,
/* Flow Director commands */
HCLGE_OPC_FD_MODE_CTRL = 0x1200,
HCLGE_OPC_FD_GET_ALLOCATION = 0x1201,
HCLGE_OPC_FD_KEY_CONFIG = 0x1202,
HCLGE_OPC_FD_TCAM_OP = 0x1203,
HCLGE_OPC_FD_AD_OP = 0x1204,
/* MDIO command */
HCLGE_OPC_MDIO_CONFIG = 0x1900,
......@@ -819,6 +826,76 @@ struct hclge_set_led_state_cmd {
u8 rsv2[20];
};
struct hclge_get_fd_mode_cmd {
u8 mode;
u8 enable;
u8 rsv[22];
};
struct hclge_get_fd_allocation_cmd {
__le32 stage1_entry_num;
__le32 stage2_entry_num;
__le16 stage1_counter_num;
__le16 stage2_counter_num;
u8 rsv[12];
};
struct hclge_set_fd_key_config_cmd {
u8 stage;
u8 key_select;
u8 inner_sipv6_word_en;
u8 inner_dipv6_word_en;
u8 outer_sipv6_word_en;
u8 outer_dipv6_word_en;
u8 rsv1[2];
__le32 tuple_mask;
__le32 meta_data_mask;
u8 rsv2[8];
};
#define HCLGE_FD_EPORT_SW_EN_B 0
struct hclge_fd_tcam_config_1_cmd {
u8 stage;
u8 xy_sel;
u8 port_info;
u8 rsv1[1];
__le32 index;
u8 entry_vld;
u8 rsv2[7];
u8 tcam_data[8];
};
struct hclge_fd_tcam_config_2_cmd {
u8 tcam_data[24];
};
struct hclge_fd_tcam_config_3_cmd {
u8 tcam_data[20];
u8 rsv[4];
};
#define HCLGE_FD_AD_DROP_B 0
#define HCLGE_FD_AD_DIRECT_QID_B 1
#define HCLGE_FD_AD_QID_S 2
#define HCLGE_FD_AD_QID_M GENMASK(12, 2)
#define HCLGE_FD_AD_USE_COUNTER_B 12
#define HCLGE_FD_AD_COUNTER_NUM_S 13
#define HCLGE_FD_AD_COUNTER_NUM_M GENMASK(20, 13)
#define HCLGE_FD_AD_NXT_STEP_B 20
#define HCLGE_FD_AD_NXT_KEY_S 21
#define HCLGE_FD_AD_NXT_KEY_M GENMASK(26, 21)
#define HCLGE_FD_AD_WR_RULE_ID_B 0
#define HCLGE_FD_AD_RULE_ID_S 1
#define HCLGE_FD_AD_RULE_ID_M GENMASK(13, 1)
struct hclge_fd_ad_config_cmd {
u8 stage;
u8 rsv1[3];
__le32 index;
__le64 ad_data;
u8 rsv2[8];
};
int hclge_cmd_init(struct hclge_dev *hdev);
static inline void hclge_write_reg(void __iomem *base, u32 reg, u32 value)
{
......
......@@ -79,6 +79,19 @@
#define HCLGE_VF_NUM_PER_CMD 64
#define HCLGE_VF_NUM_PER_BYTE 8
enum HLCGE_PORT_TYPE {
HOST_PORT,
NETWORK_PORT
};
#define HCLGE_PF_ID_S 0
#define HCLGE_PF_ID_M GENMASK(2, 0)
#define HCLGE_VF_ID_S 3
#define HCLGE_VF_ID_M GENMASK(10, 3)
#define HCLGE_PORT_TYPE_B 11
#define HCLGE_NETWORK_PORT_ID_S 0
#define HCLGE_NETWORK_PORT_ID_M GENMASK(3, 0)
/* Reset related Registers */
#define HCLGE_MISC_RESET_STS_REG 0x20700
#define HCLGE_MISC_VECTOR_INT_STS 0x20800
......@@ -359,6 +372,221 @@ struct hclge_vlan_type_cfg {
u16 tx_in_vlan_type;
};
enum HCLGE_FD_MODE {
HCLGE_FD_MODE_DEPTH_2K_WIDTH_400B_STAGE_1,
HCLGE_FD_MODE_DEPTH_1K_WIDTH_400B_STAGE_2,
HCLGE_FD_MODE_DEPTH_4K_WIDTH_200B_STAGE_1,
HCLGE_FD_MODE_DEPTH_2K_WIDTH_200B_STAGE_2,
};
enum HCLGE_FD_KEY_TYPE {
HCLGE_FD_KEY_BASE_ON_PTYPE,
HCLGE_FD_KEY_BASE_ON_TUPLE,
};
enum HCLGE_FD_STAGE {
HCLGE_FD_STAGE_1,
HCLGE_FD_STAGE_2,
};
/* OUTER_XXX indicates tuples in tunnel header of tunnel packet
* INNER_XXX indicate tuples in tunneled header of tunnel packet or
* tuples of non-tunnel packet
*/
enum HCLGE_FD_TUPLE {
OUTER_DST_MAC,
OUTER_SRC_MAC,
OUTER_VLAN_TAG_FST,
OUTER_VLAN_TAG_SEC,
OUTER_ETH_TYPE,
OUTER_L2_RSV,
OUTER_IP_TOS,
OUTER_IP_PROTO,
OUTER_SRC_IP,
OUTER_DST_IP,
OUTER_L3_RSV,
OUTER_SRC_PORT,
OUTER_DST_PORT,
OUTER_L4_RSV,
OUTER_TUN_VNI,
OUTER_TUN_FLOW_ID,
INNER_DST_MAC,
INNER_SRC_MAC,
INNER_VLAN_TAG_FST,
INNER_VLAN_TAG_SEC,
INNER_ETH_TYPE,
INNER_L2_RSV,
INNER_IP_TOS,
INNER_IP_PROTO,
INNER_SRC_IP,
INNER_DST_IP,
INNER_L3_RSV,
INNER_SRC_PORT,
INNER_DST_PORT,
INNER_L4_RSV,
MAX_TUPLE,
};
enum HCLGE_FD_META_DATA {
PACKET_TYPE_ID,
IP_FRAGEMENT,
ROCE_TYPE,
NEXT_KEY,
VLAN_NUMBER,
SRC_VPORT,
DST_VPORT,
TUNNEL_PACKET,
MAX_META_DATA,
};
struct key_info {
u8 key_type;
u8 key_length;
};
static const struct key_info meta_data_key_info[] = {
{ PACKET_TYPE_ID, 6},
{ IP_FRAGEMENT, 1},
{ ROCE_TYPE, 1},
{ NEXT_KEY, 5},
{ VLAN_NUMBER, 2},
{ SRC_VPORT, 12},
{ DST_VPORT, 12},
{ TUNNEL_PACKET, 1},
};
static const struct key_info tuple_key_info[] = {
{ OUTER_DST_MAC, 48},
{ OUTER_SRC_MAC, 48},
{ OUTER_VLAN_TAG_FST, 16},
{ OUTER_VLAN_TAG_SEC, 16},
{ OUTER_ETH_TYPE, 16},
{ OUTER_L2_RSV, 16},
{ OUTER_IP_TOS, 8},
{ OUTER_IP_PROTO, 8},
{ OUTER_SRC_IP, 32},
{ OUTER_DST_IP, 32},
{ OUTER_L3_RSV, 16},
{ OUTER_SRC_PORT, 16},
{ OUTER_DST_PORT, 16},
{ OUTER_L4_RSV, 32},
{ OUTER_TUN_VNI, 24},
{ OUTER_TUN_FLOW_ID, 8},
{ INNER_DST_MAC, 48},
{ INNER_SRC_MAC, 48},
{ INNER_VLAN_TAG_FST, 16},
{ INNER_VLAN_TAG_SEC, 16},
{ INNER_ETH_TYPE, 16},
{ INNER_L2_RSV, 16},
{ INNER_IP_TOS, 8},
{ INNER_IP_PROTO, 8},
{ INNER_SRC_IP, 32},
{ INNER_DST_IP, 32},
{ INNER_L3_RSV, 16},
{ INNER_SRC_PORT, 16},
{ INNER_DST_PORT, 16},
{ INNER_L4_RSV, 32},
};
#define MAX_KEY_LENGTH 400
#define MAX_KEY_DWORDS DIV_ROUND_UP(MAX_KEY_LENGTH / 8, 4)
#define MAX_KEY_BYTES (MAX_KEY_DWORDS * 4)
#define MAX_META_DATA_LENGTH 32
enum HCLGE_FD_PACKET_TYPE {
NIC_PACKET,
ROCE_PACKET,
};
enum HCLGE_FD_ACTION {
HCLGE_FD_ACTION_ACCEPT_PACKET,
HCLGE_FD_ACTION_DROP_PACKET,
};
struct hclge_fd_key_cfg {
u8 key_sel;
u8 inner_sipv6_word_en;
u8 inner_dipv6_word_en;
u8 outer_sipv6_word_en;
u8 outer_dipv6_word_en;
u32 tuple_active;
u32 meta_data_active;
};
struct hclge_fd_cfg {
u8 fd_mode;
u8 fd_en;
u16 max_key_length;
u32 proto_support;
u32 rule_num[2]; /* rule entry number */
u16 cnt_num[2]; /* rule hit counter number */
struct hclge_fd_key_cfg key_cfg[2];
};
struct hclge_fd_rule_tuples {
u8 src_mac[6];
u8 dst_mac[6];
u32 src_ip[4];
u32 dst_ip[4];
u16 src_port;
u16 dst_port;
u16 vlan_tag1;
u16 ether_proto;
u8 ip_tos;
u8 ip_proto;
};
struct hclge_fd_rule {
struct hlist_node rule_node;
struct hclge_fd_rule_tuples tuples;
struct hclge_fd_rule_tuples tuples_mask;
u32 unused_tuple;
u32 flow_type;
u8 action;
u16 vf_id;
u16 queue_id;
u16 location;
};
struct hclge_fd_ad_data {
u16 ad_id;
u8 drop_packet;
u8 forward_to_direct_queue;
u16 queue_id;
u8 use_counter;
u8 counter_id;
u8 use_next_stage;
u8 write_rule_id_to_bd;
u8 next_input_key;
u16 rule_id;
};
/* For each bit of TCAM entry, it uses a pair of 'x' and
* 'y' to indicate which value to match, like below:
* ----------------------------------
* | bit x | bit y | search value |
* ----------------------------------
* | 0 | 0 | always hit |
* ----------------------------------
* | 1 | 0 | match '0' |
* ----------------------------------
* | 0 | 1 | match '1' |
* ----------------------------------
* | 1 | 1 | invalid |
* ----------------------------------
* Then for input key(k) and mask(v), we can calculate the value by
* the formulae:
* x = (~k) & v
* y = (k ^ ~v) & k
*/
#define calc_x(x, k, v) ((x) = (~(k) & (v)))
#define calc_y(y, k, v) \
do { \
const typeof(k) _k_ = (k); \
const typeof(v) _v_ = (v); \
(y) = (_k_ ^ ~_v_) & (_k_); \
} while (0)
#define HCLGE_VPORT_NUM 256
struct hclge_dev {
struct pci_dev *pdev;
......@@ -448,6 +676,10 @@ struct hclge_dev {
struct hclge_vlan_type_cfg vlan_type_cfg;
unsigned long vlan_table[VLAN_N_VID][BITS_TO_LONGS(HCLGE_VPORT_NUM)];
struct hclge_fd_cfg fd_cfg;
struct hlist_head fd_rule_list;
u16 hclge_fd_rule_num;
};
/* VPort level vlan tag configuration for TX direction */
......
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