Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b25ba113 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'net-hns3-add-aRFS-feature-and-fix-FEC-bugs-for-HNS3-driver'



Huazhong Tan says:

====================
net: hns3: add aRFS feature and fix FEC bugs for HNS3 driver

This patchset adds some new features support and fixes some bugs:
[Patch 1/4 - 3/4] adds support for aRFS
[Patch 4/4] fix FEC configuration issue
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 18e88171 f438bfe9
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -343,6 +343,8 @@ struct hnae3_ae_dev {
 *   Enable/disable hardware strip vlan tag of packets received
 * set_gro_en
 *   Enable/disable HW GRO
 * add_arfs_entry
 *   Check the 5-tuples of flow, and create flow director rule
 */
struct hnae3_ae_ops {
	int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
@@ -492,6 +494,8 @@ struct hnae3_ae_ops {
				struct ethtool_rxnfc *cmd, u32 *rule_locs);
	int (*restore_fd_rules)(struct hnae3_handle *handle);
	void (*enable_fd)(struct hnae3_handle *handle, bool enable);
	int (*add_arfs_entry)(struct hnae3_handle *handle, u16 queue_id,
			      u16 flow_id, struct flow_keys *fkeys);
	int (*dbg_run_cmd)(struct hnae3_handle *handle, char *cmd_buf);
	pci_ers_result_t (*handle_hw_ras_error)(struct hnae3_ae_dev *ae_dev);
	bool (*get_hw_reset_stat)(struct hnae3_handle *handle);
+79 −29
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@
#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
#include <linux/interrupt.h>
#ifdef CONFIG_RFS_ACCEL
#include <linux/cpu_rmap.h>
#endif
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
@@ -79,23 +82,6 @@ static irqreturn_t hns3_irq_handle(int irq, void *vector)
	return IRQ_HANDLED;
}

/* This callback function is used to set affinity changes to the irq affinity
 * masks when the irq_set_affinity_notifier function is used.
 */
static void hns3_nic_irq_affinity_notify(struct irq_affinity_notify *notify,
					 const cpumask_t *mask)
{
	struct hns3_enet_tqp_vector *tqp_vectors =
		container_of(notify, struct hns3_enet_tqp_vector,
			     affinity_notify);

	tqp_vectors->affinity_mask = *mask;
}

static void hns3_nic_irq_affinity_release(struct kref *ref)
{
}

static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv)
{
	struct hns3_enet_tqp_vector *tqp_vectors;
@@ -107,8 +93,7 @@ static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv)
		if (tqp_vectors->irq_init_flag != HNS3_VECTOR_INITED)
			continue;

		/* clear the affinity notifier and affinity mask */
		irq_set_affinity_notifier(tqp_vectors->vector_irq, NULL);
		/* clear the affinity mask */
		irq_set_affinity_hint(tqp_vectors->vector_irq, NULL);

		/* release the irq resource */
@@ -161,12 +146,6 @@ static int hns3_nic_init_irq(struct hns3_nic_priv *priv)
			return ret;
		}

		tqp_vectors->affinity_notify.notify =
					hns3_nic_irq_affinity_notify;
		tqp_vectors->affinity_notify.release =
					hns3_nic_irq_affinity_release;
		irq_set_affinity_notifier(tqp_vectors->vector_irq,
					  &tqp_vectors->affinity_notify);
		irq_set_affinity_hint(tqp_vectors->vector_irq,
				      &tqp_vectors->affinity_mask);

@@ -340,6 +319,40 @@ static void hns3_tqp_disable(struct hnae3_queue *tqp)
	hns3_write_dev(tqp, HNS3_RING_EN_REG, rcb_reg);
}

static void hns3_free_rx_cpu_rmap(struct net_device *netdev)
{
#ifdef CONFIG_RFS_ACCEL
	free_irq_cpu_rmap(netdev->rx_cpu_rmap);
	netdev->rx_cpu_rmap = NULL;
#endif
}

static int hns3_set_rx_cpu_rmap(struct net_device *netdev)
{
#ifdef CONFIG_RFS_ACCEL
	struct hns3_nic_priv *priv = netdev_priv(netdev);
	struct hns3_enet_tqp_vector *tqp_vector;
	int i, ret;

	if (!netdev->rx_cpu_rmap) {
		netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(priv->vector_num);
		if (!netdev->rx_cpu_rmap)
			return -ENOMEM;
	}

	for (i = 0; i < priv->vector_num; i++) {
		tqp_vector = &priv->tqp_vector[i];
		ret = irq_cpu_rmap_add(netdev->rx_cpu_rmap,
				       tqp_vector->vector_irq);
		if (ret) {
			hns3_free_rx_cpu_rmap(netdev);
			return ret;
		}
	}
#endif
	return 0;
}

static int hns3_nic_net_up(struct net_device *netdev)
{
	struct hns3_nic_priv *priv = netdev_priv(netdev);
@@ -351,11 +364,16 @@ static int hns3_nic_net_up(struct net_device *netdev)
	if (ret)
		return ret;

	/* the device can work without cpu rmap, only aRFS needs it */
	ret = hns3_set_rx_cpu_rmap(netdev);
	if (ret)
		netdev_warn(netdev, "set rx cpu rmap fail, ret=%d!\n", ret);

	/* get irq resource for all vectors */
	ret = hns3_nic_init_irq(priv);
	if (ret) {
		netdev_err(netdev, "hns init irq failed! ret=%d\n", ret);
		return ret;
		goto free_rmap;
	}

	clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
@@ -384,7 +402,8 @@ static int hns3_nic_net_up(struct net_device *netdev)
		hns3_vector_disable(&priv->tqp_vector[j]);

	hns3_nic_uninit_irq(priv);

free_rmap:
	hns3_free_rx_cpu_rmap(netdev);
	return ret;
}

@@ -467,6 +486,8 @@ static void hns3_nic_net_down(struct net_device *netdev)
	if (ops->stop)
		ops->stop(priv->ae_handle);

	hns3_free_rx_cpu_rmap(netdev);

	/* free irq resources */
	hns3_nic_uninit_irq(priv);

@@ -1722,6 +1743,32 @@ static void hns3_nic_net_timeout(struct net_device *ndev)
		h->ae_algo->ops->reset_event(h->pdev, h);
}

#ifdef CONFIG_RFS_ACCEL
static int hns3_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
			      u16 rxq_index, u32 flow_id)
{
	struct hnae3_handle *h = hns3_get_handle(dev);
	struct flow_keys fkeys;

	if (!h->ae_algo->ops->add_arfs_entry)
		return -EOPNOTSUPP;

	if (skb->encapsulation)
		return -EPROTONOSUPPORT;

	if (!skb_flow_dissect_flow_keys(skb, &fkeys, 0))
		return -EPROTONOSUPPORT;

	if ((fkeys.basic.n_proto != htons(ETH_P_IP) &&
	     fkeys.basic.n_proto != htons(ETH_P_IPV6)) ||
	    (fkeys.basic.ip_proto != IPPROTO_TCP &&
	     fkeys.basic.ip_proto != IPPROTO_UDP))
		return -EPROTONOSUPPORT;

	return h->ae_algo->ops->add_arfs_entry(h, rxq_index, flow_id, &fkeys);
}
#endif

static const struct net_device_ops hns3_nic_netdev_ops = {
	.ndo_open		= hns3_nic_net_open,
	.ndo_stop		= hns3_nic_net_stop,
@@ -1737,6 +1784,10 @@ static const struct net_device_ops hns3_nic_netdev_ops = {
	.ndo_vlan_rx_add_vid	= hns3_vlan_rx_add_vid,
	.ndo_vlan_rx_kill_vid	= hns3_vlan_rx_kill_vid,
	.ndo_set_vf_vlan	= hns3_ndo_set_vf_vlan,
#ifdef CONFIG_RFS_ACCEL
	.ndo_rx_flow_steer	= hns3_rx_flow_steer,
#endif

};

bool hns3_is_phys_func(struct pci_dev *pdev)
@@ -2828,6 +2879,7 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
		return ret;
	}

	skb_record_rx_queue(skb, ring->tqp->tqp_index);
	*out_skb = skb;

	return 0;
@@ -3331,8 +3383,6 @@ static void hns3_nic_uninit_vector_data(struct hns3_nic_priv *priv)
		hns3_free_vector_ring_chain(tqp_vector, &vector_ring_chain);

		if (tqp_vector->irq_init_flag == HNS3_VECTOR_INITED) {
			irq_set_affinity_notifier(tqp_vector->vector_irq,
						  NULL);
			irq_set_affinity_hint(tqp_vector->vector_irq, NULL);
			free_irq(tqp_vector->vector_irq, tqp_vector);
			tqp_vector->irq_init_flag = HNS3_VECTOR_NOT_INITED;
+305 −31
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev);
static bool hclge_get_hw_reset_stat(struct hnae3_handle *handle);
static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size,
			       u16 *allocated_size, bool is_alloc);
static void hclge_rfs_filter_expire(struct hclge_dev *hdev);
static void hclge_clear_arfs_rules(struct hnae3_handle *handle);

static struct hnae3_ae_algo ae_algo;

@@ -1226,8 +1228,10 @@ static int hclge_configure(struct hclge_dev *hdev)
	hdev->tm_info.hw_pfc_map = 0;
	hdev->wanted_umv_size = cfg.umv_space;

	if (hnae3_dev_fd_supported(hdev))
	if (hnae3_dev_fd_supported(hdev)) {
		hdev->fd_en = true;
		hdev->fd_active_type = HCLGE_FD_RULE_NONE;
	}

	ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed);
	if (ret) {
@@ -2508,6 +2512,9 @@ static void hclge_update_link_status(struct hclge_dev *hdev)

static void hclge_update_port_capability(struct hclge_mac *mac)
{
	/* update fec ability by speed */
	hclge_convert_setting_fec(mac);

	/* firmware can not identify back plane type, the media type
	 * read from configuration can help deal it
	 */
@@ -2580,6 +2587,10 @@ static int hclge_get_sfp_info(struct hclge_dev *hdev, struct hclge_mac *mac)
		mac->speed_ability = le32_to_cpu(resp->speed_ability);
		mac->autoneg = resp->autoneg;
		mac->support_autoneg = resp->autoneg_ability;
		if (!resp->active_fec)
			mac->fec_mode = 0;
		else
			mac->fec_mode = BIT(resp->active_fec);
	} else {
		mac->speed_type = QUERY_SFP_SPEED;
	}
@@ -2645,6 +2656,7 @@ static void hclge_service_timer(struct timer_list *t)

	mod_timer(&hdev->service_timer, jiffies + HZ);
	hdev->hw_stats.stats_timer++;
	hdev->fd_arfs_expire_timer++;
	hclge_task_schedule(hdev);
}

@@ -3521,6 +3533,10 @@ static void hclge_service_task(struct work_struct *work)
	hclge_update_port_info(hdev);
	hclge_update_link_status(hdev);
	hclge_update_vport_alive(hdev);
	if (hdev->fd_arfs_expire_timer >= HCLGE_FD_ARFS_EXPIRE_TIMER_INTERVAL) {
		hclge_rfs_filter_expire(hdev);
		hdev->fd_arfs_expire_timer = 0;
	}
	hclge_service_complete(hdev);
}

@@ -4906,14 +4922,18 @@ static bool hclge_fd_rule_exist(struct hclge_dev *hdev, u16 location)
	struct hclge_fd_rule *rule = NULL;
	struct hlist_node *node2;

	spin_lock_bh(&hdev->fd_rule_lock);
	hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
		if (rule->location >= location)
			break;
	}

	spin_unlock_bh(&hdev->fd_rule_lock);

	return  rule && rule->location == location;
}

/* make sure being called after lock up with fd_rule_lock */
static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
				     struct hclge_fd_rule *new_rule,
				     u16 location,
@@ -4937,9 +4957,13 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
		kfree(rule);
		hdev->hclge_fd_rule_num--;

		if (!is_add)
			return 0;
		if (!is_add) {
			if (!hdev->hclge_fd_rule_num)
				hdev->fd_active_type = HCLGE_FD_RULE_NONE;
			clear_bit(location, hdev->fd_bmap);

			return 0;
		}
	} else if (!is_add) {
		dev_err(&hdev->pdev->dev,
			"delete fail, rule %d is inexistent\n",
@@ -4954,7 +4978,9 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
	else
		hlist_add_head(&new_rule->rule_node, &hdev->fd_rule_list);

	set_bit(location, hdev->fd_bmap);
	hdev->hclge_fd_rule_num++;
	hdev->fd_active_type = new_rule->rule_type;

	return 0;
}
@@ -5112,6 +5138,36 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev,
	return 0;
}

/* make sure being called after lock up with fd_rule_lock */
static int hclge_fd_config_rule(struct hclge_dev *hdev,
				struct hclge_fd_rule *rule)
{
	int ret;

	if (!rule) {
		dev_err(&hdev->pdev->dev,
			"The flow director rule is NULL\n");
		return -EINVAL;
	}

	/* it will never fail here, so needn't to check return value */
	hclge_fd_update_rule_list(hdev, rule, rule->location, true);

	ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
	if (ret)
		goto clear_rule;

	ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
	if (ret)
		goto clear_rule;

	return 0;

clear_rule:
	hclge_fd_update_rule_list(hdev, rule, rule->location, false);
	return ret;
}

static int hclge_add_fd_entry(struct hnae3_handle *handle,
			      struct ethtool_rxnfc *cmd)
{
@@ -5174,8 +5230,10 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
		return -ENOMEM;

	ret = hclge_fd_get_tuple(hdev, fs, rule);
	if (ret)
		goto free_rule;
	if (ret) {
		kfree(rule);
		return ret;
	}

	rule->flow_type = fs->flow_type;

@@ -5184,23 +5242,18 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
	rule->vf_id = dst_vport_id;
	rule->queue_id = q_index;
	rule->action = action;
	rule->rule_type = HCLGE_FD_EP_ACTIVE;

	ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
	if (ret)
		goto free_rule;

	ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
	if (ret)
		goto free_rule;
	/* to avoid rule conflict, when user configure rule by ethtool,
	 * we need to clear all arfs rules
	 */
	hclge_clear_arfs_rules(handle);

	ret = hclge_fd_update_rule_list(hdev, rule, fs->location, true);
	if (ret)
		goto free_rule;
	spin_lock_bh(&hdev->fd_rule_lock);
	ret = hclge_fd_config_rule(hdev, rule);

	return ret;
	spin_unlock_bh(&hdev->fd_rule_lock);

free_rule:
	kfree(rule);
	return ret;
}

@@ -5232,8 +5285,12 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle,
	if (ret)
		return ret;

	return hclge_fd_update_rule_list(hdev, NULL, fs->location,
					 false);
	spin_lock_bh(&hdev->fd_rule_lock);
	ret = hclge_fd_update_rule_list(hdev, NULL, fs->location, false);

	spin_unlock_bh(&hdev->fd_rule_lock);

	return ret;
}

static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
@@ -5243,25 +5300,30 @@ static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
	struct hclge_dev *hdev = vport->back;
	struct hclge_fd_rule *rule;
	struct hlist_node *node;
	u16 location;

	if (!hnae3_dev_fd_supported(hdev))
		return;

	spin_lock_bh(&hdev->fd_rule_lock);
	for_each_set_bit(location, hdev->fd_bmap,
			 hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
		hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, location,
				     NULL, false);

	if (clear_list) {
		hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
					  rule_node) {
			hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
					     rule->location, NULL, false);
			hlist_del(&rule->rule_node);
			kfree(rule);
			hdev->hclge_fd_rule_num--;
		}
	} else {
		hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
					  rule_node)
			hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
					     rule->location, NULL, false);
		hdev->fd_active_type = HCLGE_FD_RULE_NONE;
		hdev->hclge_fd_rule_num = 0;
		bitmap_zero(hdev->fd_bmap,
			    hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]);
	}

	spin_unlock_bh(&hdev->fd_rule_lock);
}

static int hclge_restore_fd_entries(struct hnae3_handle *handle)
@@ -5283,6 +5345,7 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle)
	if (!hdev->fd_en)
		return 0;

	spin_lock_bh(&hdev->fd_rule_lock);
	hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
		ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
		if (!ret)
@@ -5292,11 +5355,18 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle)
			dev_warn(&hdev->pdev->dev,
				 "Restore rule %d failed, remove it\n",
				 rule->location);
			clear_bit(rule->location, hdev->fd_bmap);
			hlist_del(&rule->rule_node);
			kfree(rule);
			hdev->hclge_fd_rule_num--;
		}
	}

	if (hdev->hclge_fd_rule_num)
		hdev->fd_active_type = HCLGE_FD_EP_ACTIVE;

	spin_unlock_bh(&hdev->fd_rule_lock);

	return 0;
}

@@ -5329,13 +5399,18 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,

	fs = (struct ethtool_rx_flow_spec *)&cmd->fs;

	spin_lock_bh(&hdev->fd_rule_lock);

	hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
		if (rule->location >= fs->location)
			break;
	}

	if (!rule || fs->location != rule->location)
	if (!rule || fs->location != rule->location) {
		spin_unlock_bh(&hdev->fd_rule_lock);

		return -ENOENT;
	}

	fs->flow_type = rule->flow_type;
	switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
@@ -5474,6 +5549,7 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,

		break;
	default:
		spin_unlock_bh(&hdev->fd_rule_lock);
		return -EOPNOTSUPP;
	}

@@ -5505,6 +5581,8 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
		fs->ring_cookie |= vf_id;
	}

	spin_unlock_bh(&hdev->fd_rule_lock);

	return 0;
}

@@ -5522,20 +5600,210 @@ static int hclge_get_all_rules(struct hnae3_handle *handle,

	cmd->data = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1];

	spin_lock_bh(&hdev->fd_rule_lock);
	hlist_for_each_entry_safe(rule, node2,
				  &hdev->fd_rule_list, rule_node) {
		if (cnt == cmd->rule_cnt)
		if (cnt == cmd->rule_cnt) {
			spin_unlock_bh(&hdev->fd_rule_lock);
			return -EMSGSIZE;
		}

		rule_locs[cnt] = rule->location;
		cnt++;
	}

	spin_unlock_bh(&hdev->fd_rule_lock);

	cmd->rule_cnt = cnt;

	return 0;
}

static void hclge_fd_get_flow_tuples(const struct flow_keys *fkeys,
				     struct hclge_fd_rule_tuples *tuples)
{
	tuples->ether_proto = be16_to_cpu(fkeys->basic.n_proto);
	tuples->ip_proto = fkeys->basic.ip_proto;
	tuples->dst_port = be16_to_cpu(fkeys->ports.dst);

	if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
		tuples->src_ip[3] = be32_to_cpu(fkeys->addrs.v4addrs.src);
		tuples->dst_ip[3] = be32_to_cpu(fkeys->addrs.v4addrs.dst);
	} else {
		memcpy(tuples->src_ip,
		       fkeys->addrs.v6addrs.src.in6_u.u6_addr32,
		       sizeof(tuples->src_ip));
		memcpy(tuples->dst_ip,
		       fkeys->addrs.v6addrs.dst.in6_u.u6_addr32,
		       sizeof(tuples->dst_ip));
	}
}

/* traverse all rules, check whether an existed rule has the same tuples */
static struct hclge_fd_rule *
hclge_fd_search_flow_keys(struct hclge_dev *hdev,
			  const struct hclge_fd_rule_tuples *tuples)
{
	struct hclge_fd_rule *rule = NULL;
	struct hlist_node *node;

	hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
		if (!memcmp(tuples, &rule->tuples, sizeof(*tuples)))
			return rule;
	}

	return NULL;
}

static void hclge_fd_build_arfs_rule(const struct hclge_fd_rule_tuples *tuples,
				     struct hclge_fd_rule *rule)
{
	rule->unused_tuple = BIT(INNER_SRC_MAC) | BIT(INNER_DST_MAC) |
			     BIT(INNER_VLAN_TAG_FST) | BIT(INNER_IP_TOS) |
			     BIT(INNER_SRC_PORT);
	rule->action = 0;
	rule->vf_id = 0;
	rule->rule_type = HCLGE_FD_ARFS_ACTIVE;
	if (tuples->ether_proto == ETH_P_IP) {
		if (tuples->ip_proto == IPPROTO_TCP)
			rule->flow_type = TCP_V4_FLOW;
		else
			rule->flow_type = UDP_V4_FLOW;
	} else {
		if (tuples->ip_proto == IPPROTO_TCP)
			rule->flow_type = TCP_V6_FLOW;
		else
			rule->flow_type = UDP_V6_FLOW;
	}
	memcpy(&rule->tuples, tuples, sizeof(rule->tuples));
	memset(&rule->tuples_mask, 0xFF, sizeof(rule->tuples_mask));
}

static int hclge_add_fd_entry_by_arfs(struct hnae3_handle *handle, u16 queue_id,
				      u16 flow_id, struct flow_keys *fkeys)
{
#ifdef CONFIG_RFS_ACCEL
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_fd_rule_tuples new_tuples;
	struct hclge_dev *hdev = vport->back;
	struct hclge_fd_rule *rule;
	u16 tmp_queue_id;
	u16 bit_id;
	int ret;

	if (!hnae3_dev_fd_supported(hdev))
		return -EOPNOTSUPP;

	memset(&new_tuples, 0, sizeof(new_tuples));
	hclge_fd_get_flow_tuples(fkeys, &new_tuples);

	spin_lock_bh(&hdev->fd_rule_lock);

	/* when there is already fd rule existed add by user,
	 * arfs should not work
	 */
	if (hdev->fd_active_type == HCLGE_FD_EP_ACTIVE) {
		spin_unlock_bh(&hdev->fd_rule_lock);

		return -EOPNOTSUPP;
	}

	/* check is there flow director filter existed for this flow,
	 * if not, create a new filter for it;
	 * if filter exist with different queue id, modify the filter;
	 * if filter exist with same queue id, do nothing
	 */
	rule = hclge_fd_search_flow_keys(hdev, &new_tuples);
	if (!rule) {
		bit_id = find_first_zero_bit(hdev->fd_bmap, MAX_FD_FILTER_NUM);
		if (bit_id >= hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]) {
			spin_unlock_bh(&hdev->fd_rule_lock);

			return -ENOSPC;
		}

		rule = kzalloc(sizeof(*rule), GFP_KERNEL);
		if (!rule) {
			spin_unlock_bh(&hdev->fd_rule_lock);

			return -ENOMEM;
		}

		set_bit(bit_id, hdev->fd_bmap);
		rule->location = bit_id;
		rule->flow_id = flow_id;
		rule->queue_id = queue_id;
		hclge_fd_build_arfs_rule(&new_tuples, rule);
		ret = hclge_fd_config_rule(hdev, rule);

		spin_unlock_bh(&hdev->fd_rule_lock);

		if (ret)
			return ret;

		return rule->location;
	}

	spin_unlock_bh(&hdev->fd_rule_lock);

	if (rule->queue_id == queue_id)
		return rule->location;

	tmp_queue_id = rule->queue_id;
	rule->queue_id = queue_id;
	ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
	if (ret) {
		rule->queue_id = tmp_queue_id;
		return ret;
	}

	return rule->location;
#endif
}

static void hclge_rfs_filter_expire(struct hclge_dev *hdev)
{
#ifdef CONFIG_RFS_ACCEL
	struct hnae3_handle *handle = &hdev->vport[0].nic;
	struct hclge_fd_rule *rule;
	struct hlist_node *node;
	HLIST_HEAD(del_list);

	spin_lock_bh(&hdev->fd_rule_lock);
	if (hdev->fd_active_type != HCLGE_FD_ARFS_ACTIVE) {
		spin_unlock_bh(&hdev->fd_rule_lock);
		return;
	}
	hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
		if (rps_may_expire_flow(handle->netdev, rule->queue_id,
					rule->flow_id, rule->location)) {
			hlist_del_init(&rule->rule_node);
			hlist_add_head(&rule->rule_node, &del_list);
			hdev->hclge_fd_rule_num--;
			clear_bit(rule->location, hdev->fd_bmap);
		}
	}
	spin_unlock_bh(&hdev->fd_rule_lock);

	hlist_for_each_entry_safe(rule, node, &del_list, rule_node) {
		hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
				     rule->location, NULL, false);
		kfree(rule);
	}
#endif
}

static void hclge_clear_arfs_rules(struct hnae3_handle *handle)
{
#ifdef CONFIG_RFS_ACCEL
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_dev *hdev = vport->back;

	if (hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE)
		hclge_del_all_fd_entries(handle, true);
#endif
}

static bool hclge_get_hw_reset_stat(struct hnae3_handle *handle)
{
	struct hclge_vport *vport = hclge_get_vport(handle);
@@ -5565,10 +5833,12 @@ static void hclge_enable_fd(struct hnae3_handle *handle, bool enable)
{
	struct hclge_vport *vport = hclge_get_vport(handle);
	struct hclge_dev *hdev = vport->back;
	bool clear;

	hdev->fd_en = enable;
	clear = hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE ? true : false;
	if (!enable)
		hclge_del_all_fd_entries(handle, false);
		hclge_del_all_fd_entries(handle, clear);
	else
		hclge_restore_fd_entries(handle);
}
@@ -5838,6 +6108,8 @@ static void hclge_ae_stop(struct hnae3_handle *handle)

	set_bit(HCLGE_STATE_DOWN, &hdev->state);

	hclge_clear_arfs_rules(handle);

	/* If it is not PF reset, the firmware will disable the MAC,
	 * so it only need to stop phy here.
	 */
@@ -8143,6 +8415,7 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)

	mutex_init(&hdev->vport_lock);
	mutex_init(&hdev->vport_cfg_mutex);
	spin_lock_init(&hdev->fd_rule_lock);

	ret = hclge_pci_init(hdev);
	if (ret) {
@@ -8908,6 +9181,7 @@ static const struct hnae3_ae_ops hclge_ops = {
	.get_fd_all_rules = hclge_get_all_rules,
	.restore_fd_rules = hclge_restore_fd_entries,
	.enable_fd = hclge_enable_fd,
	.add_arfs_entry = hclge_add_fd_entry_by_arfs,
	.dbg_run_cmd = hclge_dbg_run_cmd,
	.handle_hw_ras_error = hclge_handle_hw_ras_error,
	.get_hw_reset_stat = hclge_get_hw_reset_stat,
+16 −0
Original line number Diff line number Diff line
@@ -578,6 +578,16 @@ static const struct key_info tuple_key_info[] = {
#define MAX_KEY_BYTES	(MAX_KEY_DWORDS * 4)
#define MAX_META_DATA_LENGTH	32

/* assigned by firmware, the real filter number for each pf may be less */
#define MAX_FD_FILTER_NUM	4096
#define HCLGE_FD_ARFS_EXPIRE_TIMER_INTERVAL	5

enum HCLGE_FD_ACTIVE_RULE_TYPE {
	HCLGE_FD_RULE_NONE,
	HCLGE_FD_ARFS_ACTIVE,
	HCLGE_FD_EP_ACTIVE,
};

enum HCLGE_FD_PACKET_TYPE {
	NIC_PACKET,
	ROCE_PACKET,
@@ -630,6 +640,8 @@ struct hclge_fd_rule {
	u16 vf_id;
	u16 queue_id;
	u16 location;
	u16 flow_id;	/* only used for arfs */
	enum HCLGE_FD_ACTIVE_RULE_TYPE rule_type;
};

struct hclge_fd_ad_data {
@@ -809,7 +821,11 @@ struct hclge_dev {

	struct hclge_fd_cfg fd_cfg;
	struct hlist_head fd_rule_list;
	spinlock_t fd_rule_lock; /* protect fd_rule_list and fd_bmap */
	u16 hclge_fd_rule_num;
	u16 fd_arfs_expire_timer;
	unsigned long fd_bmap[BITS_TO_LONGS(MAX_FD_FILTER_NUM)];
	enum HCLGE_FD_ACTIVE_RULE_TYPE fd_active_type;
	u8 fd_en;

	u16 wanted_umv_size;