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

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
...@@ -343,6 +343,8 @@ struct hnae3_ae_dev { ...@@ -343,6 +343,8 @@ struct hnae3_ae_dev {
* Enable/disable hardware strip vlan tag of packets received * Enable/disable hardware strip vlan tag of packets received
* set_gro_en * set_gro_en
* Enable/disable HW GRO * Enable/disable HW GRO
* add_arfs_entry
* Check the 5-tuples of flow, and create flow director rule
*/ */
struct hnae3_ae_ops { struct hnae3_ae_ops {
int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev); int (*init_ae_dev)(struct hnae3_ae_dev *ae_dev);
...@@ -492,6 +494,8 @@ struct hnae3_ae_ops { ...@@ -492,6 +494,8 @@ struct hnae3_ae_ops {
struct ethtool_rxnfc *cmd, u32 *rule_locs); struct ethtool_rxnfc *cmd, u32 *rule_locs);
int (*restore_fd_rules)(struct hnae3_handle *handle); int (*restore_fd_rules)(struct hnae3_handle *handle);
void (*enable_fd)(struct hnae3_handle *handle, bool enable); 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); 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); pci_ers_result_t (*handle_hw_ras_error)(struct hnae3_ae_dev *ae_dev);
bool (*get_hw_reset_stat)(struct hnae3_handle *handle); bool (*get_hw_reset_stat)(struct hnae3_handle *handle);
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#ifdef CONFIG_RFS_ACCEL
#include <linux/cpu_rmap.h>
#endif
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
...@@ -79,23 +82,6 @@ static irqreturn_t hns3_irq_handle(int irq, void *vector) ...@@ -79,23 +82,6 @@ static irqreturn_t hns3_irq_handle(int irq, void *vector)
return IRQ_HANDLED; 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) static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv)
{ {
struct hns3_enet_tqp_vector *tqp_vectors; struct hns3_enet_tqp_vector *tqp_vectors;
...@@ -107,8 +93,7 @@ static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv) ...@@ -107,8 +93,7 @@ static void hns3_nic_uninit_irq(struct hns3_nic_priv *priv)
if (tqp_vectors->irq_init_flag != HNS3_VECTOR_INITED) if (tqp_vectors->irq_init_flag != HNS3_VECTOR_INITED)
continue; continue;
/* clear the affinity notifier and affinity mask */ /* clear the affinity mask */
irq_set_affinity_notifier(tqp_vectors->vector_irq, NULL);
irq_set_affinity_hint(tqp_vectors->vector_irq, NULL); irq_set_affinity_hint(tqp_vectors->vector_irq, NULL);
/* release the irq resource */ /* release the irq resource */
...@@ -161,12 +146,6 @@ static int hns3_nic_init_irq(struct hns3_nic_priv *priv) ...@@ -161,12 +146,6 @@ static int hns3_nic_init_irq(struct hns3_nic_priv *priv)
return ret; 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, irq_set_affinity_hint(tqp_vectors->vector_irq,
&tqp_vectors->affinity_mask); &tqp_vectors->affinity_mask);
...@@ -340,6 +319,40 @@ static void hns3_tqp_disable(struct hnae3_queue *tqp) ...@@ -340,6 +319,40 @@ static void hns3_tqp_disable(struct hnae3_queue *tqp)
hns3_write_dev(tqp, HNS3_RING_EN_REG, rcb_reg); 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) static int hns3_nic_net_up(struct net_device *netdev)
{ {
struct hns3_nic_priv *priv = netdev_priv(netdev); struct hns3_nic_priv *priv = netdev_priv(netdev);
...@@ -351,11 +364,16 @@ static int hns3_nic_net_up(struct net_device *netdev) ...@@ -351,11 +364,16 @@ static int hns3_nic_net_up(struct net_device *netdev)
if (ret) if (ret)
return 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 */ /* get irq resource for all vectors */
ret = hns3_nic_init_irq(priv); ret = hns3_nic_init_irq(priv);
if (ret) { if (ret) {
netdev_err(netdev, "hns init irq failed! ret=%d\n", 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); clear_bit(HNS3_NIC_STATE_DOWN, &priv->state);
...@@ -384,7 +402,8 @@ static int hns3_nic_net_up(struct net_device *netdev) ...@@ -384,7 +402,8 @@ static int hns3_nic_net_up(struct net_device *netdev)
hns3_vector_disable(&priv->tqp_vector[j]); hns3_vector_disable(&priv->tqp_vector[j]);
hns3_nic_uninit_irq(priv); hns3_nic_uninit_irq(priv);
free_rmap:
hns3_free_rx_cpu_rmap(netdev);
return ret; return ret;
} }
...@@ -467,6 +486,8 @@ static void hns3_nic_net_down(struct net_device *netdev) ...@@ -467,6 +486,8 @@ static void hns3_nic_net_down(struct net_device *netdev)
if (ops->stop) if (ops->stop)
ops->stop(priv->ae_handle); ops->stop(priv->ae_handle);
hns3_free_rx_cpu_rmap(netdev);
/* free irq resources */ /* free irq resources */
hns3_nic_uninit_irq(priv); hns3_nic_uninit_irq(priv);
...@@ -1722,6 +1743,32 @@ static void hns3_nic_net_timeout(struct net_device *ndev) ...@@ -1722,6 +1743,32 @@ static void hns3_nic_net_timeout(struct net_device *ndev)
h->ae_algo->ops->reset_event(h->pdev, h); 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 = { static const struct net_device_ops hns3_nic_netdev_ops = {
.ndo_open = hns3_nic_net_open, .ndo_open = hns3_nic_net_open,
.ndo_stop = hns3_nic_net_stop, .ndo_stop = hns3_nic_net_stop,
...@@ -1737,6 +1784,10 @@ static const struct net_device_ops hns3_nic_netdev_ops = { ...@@ -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_add_vid = hns3_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = hns3_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = hns3_vlan_rx_kill_vid,
.ndo_set_vf_vlan = hns3_ndo_set_vf_vlan, .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) bool hns3_is_phys_func(struct pci_dev *pdev)
...@@ -2828,6 +2879,7 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring, ...@@ -2828,6 +2879,7 @@ static int hns3_handle_rx_bd(struct hns3_enet_ring *ring,
return ret; return ret;
} }
skb_record_rx_queue(skb, ring->tqp->tqp_index);
*out_skb = skb; *out_skb = skb;
return 0; return 0;
...@@ -3331,8 +3383,6 @@ static void hns3_nic_uninit_vector_data(struct hns3_nic_priv *priv) ...@@ -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); hns3_free_vector_ring_chain(tqp_vector, &vector_ring_chain);
if (tqp_vector->irq_init_flag == HNS3_VECTOR_INITED) { 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); irq_set_affinity_hint(tqp_vector->vector_irq, NULL);
free_irq(tqp_vector->vector_irq, tqp_vector); free_irq(tqp_vector->vector_irq, tqp_vector);
tqp_vector->irq_init_flag = HNS3_VECTOR_NOT_INITED; tqp_vector->irq_init_flag = HNS3_VECTOR_NOT_INITED;
......
...@@ -35,6 +35,8 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev); ...@@ -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 bool hclge_get_hw_reset_stat(struct hnae3_handle *handle);
static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size, static int hclge_set_umv_space(struct hclge_dev *hdev, u16 space_size,
u16 *allocated_size, bool is_alloc); 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; static struct hnae3_ae_algo ae_algo;
...@@ -1226,8 +1228,10 @@ static int hclge_configure(struct hclge_dev *hdev) ...@@ -1226,8 +1228,10 @@ static int hclge_configure(struct hclge_dev *hdev)
hdev->tm_info.hw_pfc_map = 0; hdev->tm_info.hw_pfc_map = 0;
hdev->wanted_umv_size = cfg.umv_space; 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_en = true;
hdev->fd_active_type = HCLGE_FD_RULE_NONE;
}
ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed); ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed);
if (ret) { if (ret) {
...@@ -2508,6 +2512,9 @@ static void hclge_update_link_status(struct hclge_dev *hdev) ...@@ -2508,6 +2512,9 @@ static void hclge_update_link_status(struct hclge_dev *hdev)
static void hclge_update_port_capability(struct hclge_mac *mac) 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 /* firmware can not identify back plane type, the media type
* read from configuration can help deal it * 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) ...@@ -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->speed_ability = le32_to_cpu(resp->speed_ability);
mac->autoneg = resp->autoneg; mac->autoneg = resp->autoneg;
mac->support_autoneg = resp->autoneg_ability; mac->support_autoneg = resp->autoneg_ability;
if (!resp->active_fec)
mac->fec_mode = 0;
else
mac->fec_mode = BIT(resp->active_fec);
} else { } else {
mac->speed_type = QUERY_SFP_SPEED; mac->speed_type = QUERY_SFP_SPEED;
} }
...@@ -2645,6 +2656,7 @@ static void hclge_service_timer(struct timer_list *t) ...@@ -2645,6 +2656,7 @@ static void hclge_service_timer(struct timer_list *t)
mod_timer(&hdev->service_timer, jiffies + HZ); mod_timer(&hdev->service_timer, jiffies + HZ);
hdev->hw_stats.stats_timer++; hdev->hw_stats.stats_timer++;
hdev->fd_arfs_expire_timer++;
hclge_task_schedule(hdev); hclge_task_schedule(hdev);
} }
...@@ -3521,6 +3533,10 @@ static void hclge_service_task(struct work_struct *work) ...@@ -3521,6 +3533,10 @@ static void hclge_service_task(struct work_struct *work)
hclge_update_port_info(hdev); hclge_update_port_info(hdev);
hclge_update_link_status(hdev); hclge_update_link_status(hdev);
hclge_update_vport_alive(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); hclge_service_complete(hdev);
} }
...@@ -4906,14 +4922,18 @@ static bool hclge_fd_rule_exist(struct hclge_dev *hdev, u16 location) ...@@ -4906,14 +4922,18 @@ static bool hclge_fd_rule_exist(struct hclge_dev *hdev, u16 location)
struct hclge_fd_rule *rule = NULL; struct hclge_fd_rule *rule = NULL;
struct hlist_node *node2; struct hlist_node *node2;
spin_lock_bh(&hdev->fd_rule_lock);
hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) { hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
if (rule->location >= location) if (rule->location >= location)
break; break;
} }
spin_unlock_bh(&hdev->fd_rule_lock);
return rule && rule->location == location; 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, static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
struct hclge_fd_rule *new_rule, struct hclge_fd_rule *new_rule,
u16 location, u16 location,
...@@ -4937,9 +4957,13 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev, ...@@ -4937,9 +4957,13 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
kfree(rule); kfree(rule);
hdev->hclge_fd_rule_num--; hdev->hclge_fd_rule_num--;
if (!is_add) if (!is_add) {
return 0; 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) { } else if (!is_add) {
dev_err(&hdev->pdev->dev, dev_err(&hdev->pdev->dev,
"delete fail, rule %d is inexistent\n", "delete fail, rule %d is inexistent\n",
...@@ -4954,7 +4978,9 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev, ...@@ -4954,7 +4978,9 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
else else
hlist_add_head(&new_rule->rule_node, &hdev->fd_rule_list); hlist_add_head(&new_rule->rule_node, &hdev->fd_rule_list);
set_bit(location, hdev->fd_bmap);
hdev->hclge_fd_rule_num++; hdev->hclge_fd_rule_num++;
hdev->fd_active_type = new_rule->rule_type;
return 0; return 0;
} }
...@@ -5112,6 +5138,36 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev, ...@@ -5112,6 +5138,36 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev,
return 0; 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, static int hclge_add_fd_entry(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd) struct ethtool_rxnfc *cmd)
{ {
...@@ -5174,8 +5230,10 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, ...@@ -5174,8 +5230,10 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
return -ENOMEM; return -ENOMEM;
ret = hclge_fd_get_tuple(hdev, fs, rule); ret = hclge_fd_get_tuple(hdev, fs, rule);
if (ret) if (ret) {
goto free_rule; kfree(rule);
return ret;
}
rule->flow_type = fs->flow_type; rule->flow_type = fs->flow_type;
...@@ -5184,23 +5242,18 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle, ...@@ -5184,23 +5242,18 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
rule->vf_id = dst_vport_id; rule->vf_id = dst_vport_id;
rule->queue_id = q_index; rule->queue_id = q_index;
rule->action = action; rule->action = action;
rule->rule_type = HCLGE_FD_EP_ACTIVE;
ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule); /* to avoid rule conflict, when user configure rule by ethtool,
if (ret) * we need to clear all arfs rules
goto free_rule; */
hclge_clear_arfs_rules(handle);
ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
if (ret)
goto free_rule;
ret = hclge_fd_update_rule_list(hdev, rule, fs->location, true); spin_lock_bh(&hdev->fd_rule_lock);
if (ret) ret = hclge_fd_config_rule(hdev, rule);
goto free_rule;
return ret; spin_unlock_bh(&hdev->fd_rule_lock);
free_rule:
kfree(rule);
return ret; return ret;
} }
...@@ -5232,8 +5285,12 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle, ...@@ -5232,8 +5285,12 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle,
if (ret) if (ret)
return ret; return ret;
return hclge_fd_update_rule_list(hdev, NULL, fs->location, spin_lock_bh(&hdev->fd_rule_lock);
false); 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, 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, ...@@ -5243,25 +5300,30 @@ static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
struct hclge_fd_rule *rule; struct hclge_fd_rule *rule;
struct hlist_node *node; struct hlist_node *node;
u16 location;
if (!hnae3_dev_fd_supported(hdev)) if (!hnae3_dev_fd_supported(hdev))
return; 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) { if (clear_list) {
hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
rule_node) { rule_node) {
hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
rule->location, NULL, false);
hlist_del(&rule->rule_node); hlist_del(&rule->rule_node);
kfree(rule); kfree(rule);
hdev->hclge_fd_rule_num--;
} }
} else { hdev->fd_active_type = HCLGE_FD_RULE_NONE;
hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, hdev->hclge_fd_rule_num = 0;
rule_node) bitmap_zero(hdev->fd_bmap,
hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]);
rule->location, NULL, false);
} }
spin_unlock_bh(&hdev->fd_rule_lock);
} }
static int hclge_restore_fd_entries(struct hnae3_handle *handle) static int hclge_restore_fd_entries(struct hnae3_handle *handle)
...@@ -5283,6 +5345,7 @@ 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) if (!hdev->fd_en)
return 0; return 0;
spin_lock_bh(&hdev->fd_rule_lock);
hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) { hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule); ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
if (!ret) if (!ret)
...@@ -5292,11 +5355,18 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle) ...@@ -5292,11 +5355,18 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle)
dev_warn(&hdev->pdev->dev, dev_warn(&hdev->pdev->dev,
"Restore rule %d failed, remove it\n", "Restore rule %d failed, remove it\n",
rule->location); rule->location);
clear_bit(rule->location, hdev->fd_bmap);
hlist_del(&rule->rule_node); hlist_del(&rule->rule_node);
kfree(rule); kfree(rule);
hdev->hclge_fd_rule_num--; 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; return 0;
} }
...@@ -5329,13 +5399,18 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle, ...@@ -5329,13 +5399,18 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
fs = (struct ethtool_rx_flow_spec *)&cmd->fs; 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) { hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
if (rule->location >= fs->location) if (rule->location >= fs->location)
break; break;
} }
if (!rule || fs->location != rule->location) if (!rule || fs->location != rule->location) {
spin_unlock_bh(&hdev->fd_rule_lock);
return -ENOENT; return -ENOENT;
}
fs->flow_type = rule->flow_type; fs->flow_type = rule->flow_type;
switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
...@@ -5474,6 +5549,7 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle, ...@@ -5474,6 +5549,7 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
break; break;
default: default:
spin_unlock_bh(&hdev->fd_rule_lock);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -5505,6 +5581,8 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle, ...@@ -5505,6 +5581,8 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
fs->ring_cookie |= vf_id; fs->ring_cookie |= vf_id;
} }
spin_unlock_bh(&hdev->fd_rule_lock);
return 0; return 0;
} }
...@@ -5522,20 +5600,210 @@ static int hclge_get_all_rules(struct hnae3_handle *handle, ...@@ -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]; 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, hlist_for_each_entry_safe(rule, node2,
&hdev->fd_rule_list, rule_node) { &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; return -EMSGSIZE;
}
rule_locs[cnt] = rule->location; rule_locs[cnt] = rule->location;
cnt++; cnt++;
} }
spin_unlock_bh(&hdev->fd_rule_lock);
cmd->rule_cnt = cnt; cmd->rule_cnt = cnt;
return 0; 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) static bool hclge_get_hw_reset_stat(struct hnae3_handle *handle)
{ {
struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_vport *vport = hclge_get_vport(handle);
...@@ -5565,10 +5833,12 @@ static void hclge_enable_fd(struct hnae3_handle *handle, bool enable) ...@@ -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_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back; struct hclge_dev *hdev = vport->back;
bool clear;
hdev->fd_en = enable; hdev->fd_en = enable;
clear = hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE ? true : false;
if (!enable) if (!enable)
hclge_del_all_fd_entries(handle, false); hclge_del_all_fd_entries(handle, clear);
else else
hclge_restore_fd_entries(handle); hclge_restore_fd_entries(handle);
} }
...@@ -5838,6 +6108,8 @@ static void hclge_ae_stop(struct hnae3_handle *handle) ...@@ -5838,6 +6108,8 @@ static void hclge_ae_stop(struct hnae3_handle *handle)
set_bit(HCLGE_STATE_DOWN, &hdev->state); set_bit(HCLGE_STATE_DOWN, &hdev->state);
hclge_clear_arfs_rules(handle);
/* If it is not PF reset, the firmware will disable the MAC, /* If it is not PF reset, the firmware will disable the MAC,
* so it only need to stop phy here. * so it only need to stop phy here.
*/ */
...@@ -8143,6 +8415,7 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) ...@@ -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_lock);
mutex_init(&hdev->vport_cfg_mutex); mutex_init(&hdev->vport_cfg_mutex);
spin_lock_init(&hdev->fd_rule_lock);
ret = hclge_pci_init(hdev); ret = hclge_pci_init(hdev);
if (ret) { if (ret) {
...@@ -8908,6 +9181,7 @@ static const struct hnae3_ae_ops hclge_ops = { ...@@ -8908,6 +9181,7 @@ static const struct hnae3_ae_ops hclge_ops = {
.get_fd_all_rules = hclge_get_all_rules, .get_fd_all_rules = hclge_get_all_rules,
.restore_fd_rules = hclge_restore_fd_entries, .restore_fd_rules = hclge_restore_fd_entries,
.enable_fd = hclge_enable_fd, .enable_fd = hclge_enable_fd,
.add_arfs_entry = hclge_add_fd_entry_by_arfs,
.dbg_run_cmd = hclge_dbg_run_cmd, .dbg_run_cmd = hclge_dbg_run_cmd,
.handle_hw_ras_error = hclge_handle_hw_ras_error, .handle_hw_ras_error = hclge_handle_hw_ras_error,
.get_hw_reset_stat = hclge_get_hw_reset_stat, .get_hw_reset_stat = hclge_get_hw_reset_stat,
......
...@@ -578,6 +578,16 @@ static const struct key_info tuple_key_info[] = { ...@@ -578,6 +578,16 @@ static const struct key_info tuple_key_info[] = {
#define MAX_KEY_BYTES (MAX_KEY_DWORDS * 4) #define MAX_KEY_BYTES (MAX_KEY_DWORDS * 4)
#define MAX_META_DATA_LENGTH 32 #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 { enum HCLGE_FD_PACKET_TYPE {
NIC_PACKET, NIC_PACKET,
ROCE_PACKET, ROCE_PACKET,
...@@ -630,6 +640,8 @@ struct hclge_fd_rule { ...@@ -630,6 +640,8 @@ struct hclge_fd_rule {
u16 vf_id; u16 vf_id;
u16 queue_id; u16 queue_id;
u16 location; u16 location;
u16 flow_id; /* only used for arfs */
enum HCLGE_FD_ACTIVE_RULE_TYPE rule_type;
}; };
struct hclge_fd_ad_data { struct hclge_fd_ad_data {
...@@ -809,7 +821,11 @@ struct hclge_dev { ...@@ -809,7 +821,11 @@ struct hclge_dev {
struct hclge_fd_cfg fd_cfg; struct hclge_fd_cfg fd_cfg;
struct hlist_head fd_rule_list; struct hlist_head fd_rule_list;
spinlock_t fd_rule_lock; /* protect fd_rule_list and fd_bmap */
u16 hclge_fd_rule_num; 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; u8 fd_en;
u16 wanted_umv_size; u16 wanted_umv_size;
......
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