diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index ad21b0ef1946..a18645e24434 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -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); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index 196a3d780dcf..5e12705bae34 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -4,6 +4,9 @@ #include #include #include +#ifdef CONFIG_RFS_ACCEL +#include +#endif #include #include #include @@ -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; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index d3b1f8cb1155..a3fba7b8bcbb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -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,24 +5242,19 @@ 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; + /* to avoid rule conflict, when user configure rule by ethtool, + * we need to clear all arfs rules + */ + hclge_clear_arfs_rules(handle); - ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule); - if (ret) - goto free_rule; + spin_lock_bh(&hdev->fd_rule_lock); + ret = hclge_fd_config_rule(hdev, rule); - ret = hclge_fd_update_rule_list(hdev, rule, fs->location, true); - if (ret) - goto free_rule; + spin_unlock_bh(&hdev->fd_rule_lock); return ret; - -free_rule: - kfree(rule); - return ret; } 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) 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, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index dd06b11187b0..c770390c6e57 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -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;