162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/bpf.h> 3562306a36Sopenharmony_ci#include <linux/etherdevice.h> 3662306a36Sopenharmony_ci#include <linux/filter.h> 3762306a36Sopenharmony_ci#include <linux/tcp.h> 3862306a36Sopenharmony_ci#include <linux/if_vlan.h> 3962306a36Sopenharmony_ci#include <linux/delay.h> 4062306a36Sopenharmony_ci#include <linux/slab.h> 4162306a36Sopenharmony_ci#include <linux/hash.h> 4262306a36Sopenharmony_ci#include <net/ip.h> 4362306a36Sopenharmony_ci#include <net/vxlan.h> 4462306a36Sopenharmony_ci#include <net/devlink.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <linux/mlx4/driver.h> 4762306a36Sopenharmony_ci#include <linux/mlx4/device.h> 4862306a36Sopenharmony_ci#include <linux/mlx4/cmd.h> 4962306a36Sopenharmony_ci#include <linux/mlx4/cq.h> 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#include "mlx4_en.h" 5262306a36Sopenharmony_ci#include "en_port.h" 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define MLX4_EN_MAX_XDP_MTU ((int)(PAGE_SIZE - ETH_HLEN - (2 * VLAN_HLEN) - \ 5562306a36Sopenharmony_ci XDP_PACKET_HEADROOM - \ 5662306a36Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciint mlx4_en_setup_tc(struct net_device *dev, u8 up) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 6162306a36Sopenharmony_ci int i; 6262306a36Sopenharmony_ci unsigned int offset = 0; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (up && up != MLX4_EN_NUM_UP_HIGH) 6562306a36Sopenharmony_ci return -EINVAL; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci netdev_set_num_tc(dev, up); 6862306a36Sopenharmony_ci netif_set_real_num_tx_queues(dev, priv->tx_ring_num[TX]); 6962306a36Sopenharmony_ci /* Partition Tx queues evenly amongst UP's */ 7062306a36Sopenharmony_ci for (i = 0; i < up; i++) { 7162306a36Sopenharmony_ci netdev_set_tc_queue(dev, i, priv->num_tx_rings_p_up, offset); 7262306a36Sopenharmony_ci offset += priv->num_tx_rings_p_up; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#ifdef CONFIG_MLX4_EN_DCB 7662306a36Sopenharmony_ci if (!mlx4_is_slave(priv->mdev->dev)) { 7762306a36Sopenharmony_ci if (up) { 7862306a36Sopenharmony_ci if (priv->dcbx_cap) 7962306a36Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_DCB_ENABLED; 8062306a36Sopenharmony_ci } else { 8162306a36Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_DCB_ENABLED; 8262306a36Sopenharmony_ci priv->cee_config.pfc_state = false; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci#endif /* CONFIG_MLX4_EN_DCB */ 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return 0; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ciint mlx4_en_alloc_tx_queue_per_tc(struct net_device *dev, u8 tc) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 9362306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 9462306a36Sopenharmony_ci struct mlx4_en_port_profile new_prof; 9562306a36Sopenharmony_ci struct mlx4_en_priv *tmp; 9662306a36Sopenharmony_ci int total_count; 9762306a36Sopenharmony_ci int port_up = 0; 9862306a36Sopenharmony_ci int err = 0; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 10162306a36Sopenharmony_ci if (!tmp) 10262306a36Sopenharmony_ci return -ENOMEM; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 10562306a36Sopenharmony_ci memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); 10662306a36Sopenharmony_ci new_prof.num_up = (tc == 0) ? MLX4_EN_NUM_UP_LOW : 10762306a36Sopenharmony_ci MLX4_EN_NUM_UP_HIGH; 10862306a36Sopenharmony_ci new_prof.tx_ring_num[TX] = new_prof.num_tx_rings_p_up * 10962306a36Sopenharmony_ci new_prof.num_up; 11062306a36Sopenharmony_ci total_count = new_prof.tx_ring_num[TX] + new_prof.tx_ring_num[TX_XDP]; 11162306a36Sopenharmony_ci if (total_count > MAX_TX_RINGS) { 11262306a36Sopenharmony_ci err = -EINVAL; 11362306a36Sopenharmony_ci en_err(priv, 11462306a36Sopenharmony_ci "Total number of TX and XDP rings (%d) exceeds the maximum supported (%d)\n", 11562306a36Sopenharmony_ci total_count, MAX_TX_RINGS); 11662306a36Sopenharmony_ci goto out; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); 11962306a36Sopenharmony_ci if (err) 12062306a36Sopenharmony_ci goto out; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (priv->port_up) { 12362306a36Sopenharmony_ci port_up = 1; 12462306a36Sopenharmony_ci mlx4_en_stop_port(dev, 1); 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci mlx4_en_safe_replace_resources(priv, tmp); 12862306a36Sopenharmony_ci if (port_up) { 12962306a36Sopenharmony_ci err = mlx4_en_start_port(dev); 13062306a36Sopenharmony_ci if (err) { 13162306a36Sopenharmony_ci en_err(priv, "Failed starting port for setup TC\n"); 13262306a36Sopenharmony_ci goto out; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci err = mlx4_en_setup_tc(dev, tc); 13762306a36Sopenharmony_ciout: 13862306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 13962306a36Sopenharmony_ci kfree(tmp); 14062306a36Sopenharmony_ci return err; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int __mlx4_en_setup_tc(struct net_device *dev, enum tc_setup_type type, 14462306a36Sopenharmony_ci void *type_data) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct tc_mqprio_qopt *mqprio = type_data; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (type != TC_SETUP_QDISC_MQPRIO) 14962306a36Sopenharmony_ci return -EOPNOTSUPP; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (mqprio->num_tc && mqprio->num_tc != MLX4_EN_NUM_UP_HIGH) 15262306a36Sopenharmony_ci return -EINVAL; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return mlx4_en_alloc_tx_queue_per_tc(dev, mqprio->num_tc); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistruct mlx4_en_filter { 16262306a36Sopenharmony_ci struct list_head next; 16362306a36Sopenharmony_ci struct work_struct work; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci u8 ip_proto; 16662306a36Sopenharmony_ci __be32 src_ip; 16762306a36Sopenharmony_ci __be32 dst_ip; 16862306a36Sopenharmony_ci __be16 src_port; 16962306a36Sopenharmony_ci __be16 dst_port; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci int rxq_index; 17262306a36Sopenharmony_ci struct mlx4_en_priv *priv; 17362306a36Sopenharmony_ci u32 flow_id; /* RFS infrastructure id */ 17462306a36Sopenharmony_ci int id; /* mlx4_en driver id */ 17562306a36Sopenharmony_ci u64 reg_id; /* Flow steering API id */ 17662306a36Sopenharmony_ci u8 activated; /* Used to prevent expiry before filter 17762306a36Sopenharmony_ci * is attached 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci struct hlist_node filter_chain; 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic enum mlx4_net_trans_rule_id mlx4_ip_proto_to_trans_rule_id(u8 ip_proto) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci switch (ip_proto) { 18762306a36Sopenharmony_ci case IPPROTO_UDP: 18862306a36Sopenharmony_ci return MLX4_NET_TRANS_RULE_ID_UDP; 18962306a36Sopenharmony_ci case IPPROTO_TCP: 19062306a36Sopenharmony_ci return MLX4_NET_TRANS_RULE_ID_TCP; 19162306a36Sopenharmony_ci default: 19262306a36Sopenharmony_ci return MLX4_NET_TRANS_RULE_NUM; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci}; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* Must not acquire state_lock, as its corresponding work_sync 19762306a36Sopenharmony_ci * is done under it. 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_cistatic void mlx4_en_filter_work(struct work_struct *work) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct mlx4_en_filter *filter = container_of(work, 20262306a36Sopenharmony_ci struct mlx4_en_filter, 20362306a36Sopenharmony_ci work); 20462306a36Sopenharmony_ci struct mlx4_en_priv *priv = filter->priv; 20562306a36Sopenharmony_ci struct mlx4_spec_list spec_tcp_udp = { 20662306a36Sopenharmony_ci .id = mlx4_ip_proto_to_trans_rule_id(filter->ip_proto), 20762306a36Sopenharmony_ci { 20862306a36Sopenharmony_ci .tcp_udp = { 20962306a36Sopenharmony_ci .dst_port = filter->dst_port, 21062306a36Sopenharmony_ci .dst_port_msk = (__force __be16)-1, 21162306a36Sopenharmony_ci .src_port = filter->src_port, 21262306a36Sopenharmony_ci .src_port_msk = (__force __be16)-1, 21362306a36Sopenharmony_ci }, 21462306a36Sopenharmony_ci }, 21562306a36Sopenharmony_ci }; 21662306a36Sopenharmony_ci struct mlx4_spec_list spec_ip = { 21762306a36Sopenharmony_ci .id = MLX4_NET_TRANS_RULE_ID_IPV4, 21862306a36Sopenharmony_ci { 21962306a36Sopenharmony_ci .ipv4 = { 22062306a36Sopenharmony_ci .dst_ip = filter->dst_ip, 22162306a36Sopenharmony_ci .dst_ip_msk = (__force __be32)-1, 22262306a36Sopenharmony_ci .src_ip = filter->src_ip, 22362306a36Sopenharmony_ci .src_ip_msk = (__force __be32)-1, 22462306a36Sopenharmony_ci }, 22562306a36Sopenharmony_ci }, 22662306a36Sopenharmony_ci }; 22762306a36Sopenharmony_ci struct mlx4_spec_list spec_eth = { 22862306a36Sopenharmony_ci .id = MLX4_NET_TRANS_RULE_ID_ETH, 22962306a36Sopenharmony_ci }; 23062306a36Sopenharmony_ci struct mlx4_net_trans_rule rule = { 23162306a36Sopenharmony_ci .list = LIST_HEAD_INIT(rule.list), 23262306a36Sopenharmony_ci .queue_mode = MLX4_NET_TRANS_Q_LIFO, 23362306a36Sopenharmony_ci .exclusive = 1, 23462306a36Sopenharmony_ci .allow_loopback = 1, 23562306a36Sopenharmony_ci .promisc_mode = MLX4_FS_REGULAR, 23662306a36Sopenharmony_ci .port = priv->port, 23762306a36Sopenharmony_ci .priority = MLX4_DOMAIN_RFS, 23862306a36Sopenharmony_ci }; 23962306a36Sopenharmony_ci int rc; 24062306a36Sopenharmony_ci __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (spec_tcp_udp.id >= MLX4_NET_TRANS_RULE_NUM) { 24362306a36Sopenharmony_ci en_warn(priv, "RFS: ignoring unsupported ip protocol (%d)\n", 24462306a36Sopenharmony_ci filter->ip_proto); 24562306a36Sopenharmony_ci goto ignore; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci list_add_tail(&spec_eth.list, &rule.list); 24862306a36Sopenharmony_ci list_add_tail(&spec_ip.list, &rule.list); 24962306a36Sopenharmony_ci list_add_tail(&spec_tcp_udp.list, &rule.list); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn; 25262306a36Sopenharmony_ci memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN); 25362306a36Sopenharmony_ci memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci filter->activated = 0; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (filter->reg_id) { 25862306a36Sopenharmony_ci rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); 25962306a36Sopenharmony_ci if (rc && rc != -ENOENT) 26062306a36Sopenharmony_ci en_err(priv, "Error detaching flow. rc = %d\n", rc); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci rc = mlx4_flow_attach(priv->mdev->dev, &rule, &filter->reg_id); 26462306a36Sopenharmony_ci if (rc) 26562306a36Sopenharmony_ci en_err(priv, "Error attaching flow. err = %d\n", rc); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ciignore: 26862306a36Sopenharmony_ci mlx4_en_filter_rfs_expire(priv); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci filter->activated = 1; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic inline struct hlist_head * 27462306a36Sopenharmony_cifilter_hash_bucket(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, 27562306a36Sopenharmony_ci __be16 src_port, __be16 dst_port) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci unsigned long l; 27862306a36Sopenharmony_ci int bucket_idx; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci l = (__force unsigned long)src_port | 28162306a36Sopenharmony_ci ((__force unsigned long)dst_port << 2); 28262306a36Sopenharmony_ci l ^= (__force unsigned long)(src_ip ^ dst_ip); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci bucket_idx = hash_long(l, MLX4_EN_FILTER_HASH_SHIFT); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci return &priv->filter_hash[bucket_idx]; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic struct mlx4_en_filter * 29062306a36Sopenharmony_cimlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip, 29162306a36Sopenharmony_ci __be32 dst_ip, u8 ip_proto, __be16 src_port, 29262306a36Sopenharmony_ci __be16 dst_port, u32 flow_id) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct mlx4_en_filter *filter; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci filter = kzalloc(sizeof(struct mlx4_en_filter), GFP_ATOMIC); 29762306a36Sopenharmony_ci if (!filter) 29862306a36Sopenharmony_ci return NULL; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci filter->priv = priv; 30162306a36Sopenharmony_ci filter->rxq_index = rxq_index; 30262306a36Sopenharmony_ci INIT_WORK(&filter->work, mlx4_en_filter_work); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci filter->src_ip = src_ip; 30562306a36Sopenharmony_ci filter->dst_ip = dst_ip; 30662306a36Sopenharmony_ci filter->ip_proto = ip_proto; 30762306a36Sopenharmony_ci filter->src_port = src_port; 30862306a36Sopenharmony_ci filter->dst_port = dst_port; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci filter->flow_id = flow_id; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci filter->id = priv->last_filter_id++ % RPS_NO_FILTER; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci list_add_tail(&filter->next, &priv->filters); 31562306a36Sopenharmony_ci hlist_add_head(&filter->filter_chain, 31662306a36Sopenharmony_ci filter_hash_bucket(priv, src_ip, dst_ip, src_port, 31762306a36Sopenharmony_ci dst_port)); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return filter; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void mlx4_en_filter_free(struct mlx4_en_filter *filter) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct mlx4_en_priv *priv = filter->priv; 32562306a36Sopenharmony_ci int rc; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci list_del(&filter->next); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); 33062306a36Sopenharmony_ci if (rc && rc != -ENOENT) 33162306a36Sopenharmony_ci en_err(priv, "Error detaching flow. rc = %d\n", rc); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci kfree(filter); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic inline struct mlx4_en_filter * 33762306a36Sopenharmony_cimlx4_en_filter_find(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, 33862306a36Sopenharmony_ci u8 ip_proto, __be16 src_port, __be16 dst_port) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct mlx4_en_filter *filter; 34162306a36Sopenharmony_ci struct mlx4_en_filter *ret = NULL; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci hlist_for_each_entry(filter, 34462306a36Sopenharmony_ci filter_hash_bucket(priv, src_ip, dst_ip, 34562306a36Sopenharmony_ci src_port, dst_port), 34662306a36Sopenharmony_ci filter_chain) { 34762306a36Sopenharmony_ci if (filter->src_ip == src_ip && 34862306a36Sopenharmony_ci filter->dst_ip == dst_ip && 34962306a36Sopenharmony_ci filter->ip_proto == ip_proto && 35062306a36Sopenharmony_ci filter->src_port == src_port && 35162306a36Sopenharmony_ci filter->dst_port == dst_port) { 35262306a36Sopenharmony_ci ret = filter; 35362306a36Sopenharmony_ci break; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci return ret; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic int 36162306a36Sopenharmony_cimlx4_en_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, 36262306a36Sopenharmony_ci u16 rxq_index, u32 flow_id) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(net_dev); 36562306a36Sopenharmony_ci struct mlx4_en_filter *filter; 36662306a36Sopenharmony_ci const struct iphdr *ip; 36762306a36Sopenharmony_ci const __be16 *ports; 36862306a36Sopenharmony_ci u8 ip_proto; 36962306a36Sopenharmony_ci __be32 src_ip; 37062306a36Sopenharmony_ci __be32 dst_ip; 37162306a36Sopenharmony_ci __be16 src_port; 37262306a36Sopenharmony_ci __be16 dst_port; 37362306a36Sopenharmony_ci int nhoff = skb_network_offset(skb); 37462306a36Sopenharmony_ci int ret = 0; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (skb->encapsulation) 37762306a36Sopenharmony_ci return -EPROTONOSUPPORT; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (skb->protocol != htons(ETH_P_IP)) 38062306a36Sopenharmony_ci return -EPROTONOSUPPORT; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ip = (const struct iphdr *)(skb->data + nhoff); 38362306a36Sopenharmony_ci if (ip_is_fragment(ip)) 38462306a36Sopenharmony_ci return -EPROTONOSUPPORT; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if ((ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP)) 38762306a36Sopenharmony_ci return -EPROTONOSUPPORT; 38862306a36Sopenharmony_ci ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ip_proto = ip->protocol; 39162306a36Sopenharmony_ci src_ip = ip->saddr; 39262306a36Sopenharmony_ci dst_ip = ip->daddr; 39362306a36Sopenharmony_ci src_port = ports[0]; 39462306a36Sopenharmony_ci dst_port = ports[1]; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci spin_lock_bh(&priv->filters_lock); 39762306a36Sopenharmony_ci filter = mlx4_en_filter_find(priv, src_ip, dst_ip, ip_proto, 39862306a36Sopenharmony_ci src_port, dst_port); 39962306a36Sopenharmony_ci if (filter) { 40062306a36Sopenharmony_ci if (filter->rxq_index == rxq_index) 40162306a36Sopenharmony_ci goto out; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci filter->rxq_index = rxq_index; 40462306a36Sopenharmony_ci } else { 40562306a36Sopenharmony_ci filter = mlx4_en_filter_alloc(priv, rxq_index, 40662306a36Sopenharmony_ci src_ip, dst_ip, ip_proto, 40762306a36Sopenharmony_ci src_port, dst_port, flow_id); 40862306a36Sopenharmony_ci if (!filter) { 40962306a36Sopenharmony_ci ret = -ENOMEM; 41062306a36Sopenharmony_ci goto err; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci queue_work(priv->mdev->workqueue, &filter->work); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ciout: 41762306a36Sopenharmony_ci ret = filter->id; 41862306a36Sopenharmony_cierr: 41962306a36Sopenharmony_ci spin_unlock_bh(&priv->filters_lock); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return ret; 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_civoid mlx4_en_cleanup_filters(struct mlx4_en_priv *priv) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct mlx4_en_filter *filter, *tmp; 42762306a36Sopenharmony_ci LIST_HEAD(del_list); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci spin_lock_bh(&priv->filters_lock); 43062306a36Sopenharmony_ci list_for_each_entry_safe(filter, tmp, &priv->filters, next) { 43162306a36Sopenharmony_ci list_move(&filter->next, &del_list); 43262306a36Sopenharmony_ci hlist_del(&filter->filter_chain); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci spin_unlock_bh(&priv->filters_lock); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci list_for_each_entry_safe(filter, tmp, &del_list, next) { 43762306a36Sopenharmony_ci cancel_work_sync(&filter->work); 43862306a36Sopenharmony_ci mlx4_en_filter_free(filter); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct mlx4_en_filter *filter = NULL, *tmp, *last_filter = NULL; 44562306a36Sopenharmony_ci LIST_HEAD(del_list); 44662306a36Sopenharmony_ci int i = 0; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci spin_lock_bh(&priv->filters_lock); 44962306a36Sopenharmony_ci list_for_each_entry_safe(filter, tmp, &priv->filters, next) { 45062306a36Sopenharmony_ci if (i > MLX4_EN_FILTER_EXPIRY_QUOTA) 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (filter->activated && 45462306a36Sopenharmony_ci !work_pending(&filter->work) && 45562306a36Sopenharmony_ci rps_may_expire_flow(priv->dev, 45662306a36Sopenharmony_ci filter->rxq_index, filter->flow_id, 45762306a36Sopenharmony_ci filter->id)) { 45862306a36Sopenharmony_ci list_move(&filter->next, &del_list); 45962306a36Sopenharmony_ci hlist_del(&filter->filter_chain); 46062306a36Sopenharmony_ci } else 46162306a36Sopenharmony_ci last_filter = filter; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci i++; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (last_filter && (&last_filter->next != priv->filters.next)) 46762306a36Sopenharmony_ci list_move(&priv->filters, &last_filter->next); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci spin_unlock_bh(&priv->filters_lock); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci list_for_each_entry_safe(filter, tmp, &del_list, next) 47262306a36Sopenharmony_ci mlx4_en_filter_free(filter); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci#endif 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic int mlx4_en_vlan_rx_add_vid(struct net_device *dev, 47762306a36Sopenharmony_ci __be16 proto, u16 vid) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 48062306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 48162306a36Sopenharmony_ci int err; 48262306a36Sopenharmony_ci int idx; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci en_dbg(HW, priv, "adding VLAN:%d\n", vid); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci set_bit(vid, priv->active_vlans); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Add VID to port VLAN filter */ 48962306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 49062306a36Sopenharmony_ci if (mdev->device_up && priv->port_up) { 49162306a36Sopenharmony_ci err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); 49262306a36Sopenharmony_ci if (err) { 49362306a36Sopenharmony_ci en_err(priv, "Failed configuring VLAN filter\n"); 49462306a36Sopenharmony_ci goto out; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci err = mlx4_register_vlan(mdev->dev, priv->port, vid, &idx); 49862306a36Sopenharmony_ci if (err) 49962306a36Sopenharmony_ci en_dbg(HW, priv, "Failed adding vlan %d\n", vid); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ciout: 50262306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 50362306a36Sopenharmony_ci return err; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, 50762306a36Sopenharmony_ci __be16 proto, u16 vid) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 51062306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 51162306a36Sopenharmony_ci int err = 0; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci en_dbg(HW, priv, "Killing VID:%d\n", vid); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci clear_bit(vid, priv->active_vlans); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* Remove VID from port VLAN filter */ 51862306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 51962306a36Sopenharmony_ci mlx4_unregister_vlan(mdev->dev, priv->port, vid); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (mdev->device_up && priv->port_up) { 52262306a36Sopenharmony_ci err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); 52362306a36Sopenharmony_ci if (err) 52462306a36Sopenharmony_ci en_err(priv, "Failed configuring VLAN filter\n"); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return err; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic void mlx4_en_u64_to_mac(struct net_device *dev, u64 src_mac) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci u64_to_ether_addr(src_mac, addr); 53662306a36Sopenharmony_ci eth_hw_addr_set(dev, addr); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic int mlx4_en_tunnel_steer_add(struct mlx4_en_priv *priv, 54162306a36Sopenharmony_ci const unsigned char *addr, 54262306a36Sopenharmony_ci int qpn, u64 *reg_id) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci int err; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN || 54762306a36Sopenharmony_ci priv->mdev->dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC) 54862306a36Sopenharmony_ci return 0; /* do nothing */ 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci err = mlx4_tunnel_steer_add(priv->mdev->dev, addr, priv->port, qpn, 55162306a36Sopenharmony_ci MLX4_DOMAIN_NIC, reg_id); 55262306a36Sopenharmony_ci if (err) { 55362306a36Sopenharmony_ci en_err(priv, "failed to add vxlan steering rule, err %d\n", err); 55462306a36Sopenharmony_ci return err; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci en_dbg(DRV, priv, "added vxlan steering rule, mac %pM reg_id %llx\n", addr, *reg_id); 55762306a36Sopenharmony_ci return 0; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv, 56262306a36Sopenharmony_ci const unsigned char *mac, int *qpn, u64 *reg_id) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 56562306a36Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 56662306a36Sopenharmony_ci int err; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci switch (dev->caps.steering_mode) { 56962306a36Sopenharmony_ci case MLX4_STEERING_MODE_B0: { 57062306a36Sopenharmony_ci struct mlx4_qp qp; 57162306a36Sopenharmony_ci u8 gid[16] = {0}; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci qp.qpn = *qpn; 57462306a36Sopenharmony_ci memcpy(&gid[10], mac, ETH_ALEN); 57562306a36Sopenharmony_ci gid[5] = priv->port; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH); 57862306a36Sopenharmony_ci break; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: { 58162306a36Sopenharmony_ci struct mlx4_spec_list spec_eth = { {NULL} }; 58262306a36Sopenharmony_ci __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci struct mlx4_net_trans_rule rule = { 58562306a36Sopenharmony_ci .queue_mode = MLX4_NET_TRANS_Q_FIFO, 58662306a36Sopenharmony_ci .exclusive = 0, 58762306a36Sopenharmony_ci .allow_loopback = 1, 58862306a36Sopenharmony_ci .promisc_mode = MLX4_FS_REGULAR, 58962306a36Sopenharmony_ci .priority = MLX4_DOMAIN_NIC, 59062306a36Sopenharmony_ci }; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci rule.port = priv->port; 59362306a36Sopenharmony_ci rule.qpn = *qpn; 59462306a36Sopenharmony_ci INIT_LIST_HEAD(&rule.list); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH; 59762306a36Sopenharmony_ci memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN); 59862306a36Sopenharmony_ci memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 59962306a36Sopenharmony_ci list_add_tail(&spec_eth.list, &rule.list); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci err = mlx4_flow_attach(dev, &rule, reg_id); 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci default: 60562306a36Sopenharmony_ci return -EINVAL; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci if (err) 60862306a36Sopenharmony_ci en_warn(priv, "Failed Attaching Unicast\n"); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return err; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv, 61462306a36Sopenharmony_ci const unsigned char *mac, 61562306a36Sopenharmony_ci int qpn, u64 reg_id) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 61862306a36Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci switch (dev->caps.steering_mode) { 62162306a36Sopenharmony_ci case MLX4_STEERING_MODE_B0: { 62262306a36Sopenharmony_ci struct mlx4_qp qp; 62362306a36Sopenharmony_ci u8 gid[16] = {0}; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci qp.qpn = qpn; 62662306a36Sopenharmony_ci memcpy(&gid[10], mac, ETH_ALEN); 62762306a36Sopenharmony_ci gid[5] = priv->port; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH); 63062306a36Sopenharmony_ci break; 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: { 63362306a36Sopenharmony_ci mlx4_flow_detach(dev, reg_id); 63462306a36Sopenharmony_ci break; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci default: 63762306a36Sopenharmony_ci en_err(priv, "Invalid steering mode.\n"); 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int mlx4_en_get_qp(struct mlx4_en_priv *priv) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 64462306a36Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 64562306a36Sopenharmony_ci int index = 0; 64662306a36Sopenharmony_ci int err = 0; 64762306a36Sopenharmony_ci int *qpn = &priv->base_qpn; 64862306a36Sopenharmony_ci u64 mac = ether_addr_to_u64(priv->dev->dev_addr); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci en_dbg(DRV, priv, "Registering MAC: %pM for adding\n", 65162306a36Sopenharmony_ci priv->dev->dev_addr); 65262306a36Sopenharmony_ci index = mlx4_register_mac(dev, priv->port, mac); 65362306a36Sopenharmony_ci if (index < 0) { 65462306a36Sopenharmony_ci err = index; 65562306a36Sopenharmony_ci en_err(priv, "Failed adding MAC: %pM\n", 65662306a36Sopenharmony_ci priv->dev->dev_addr); 65762306a36Sopenharmony_ci return err; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci en_info(priv, "Steering Mode %d\n", dev->caps.steering_mode); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { 66362306a36Sopenharmony_ci int base_qpn = mlx4_get_base_qpn(dev, priv->port); 66462306a36Sopenharmony_ci *qpn = base_qpn + index; 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci err = mlx4_qp_reserve_range(dev, 1, 1, qpn, MLX4_RESERVE_A0_QP, 66962306a36Sopenharmony_ci MLX4_RES_USAGE_DRIVER); 67062306a36Sopenharmony_ci en_dbg(DRV, priv, "Reserved qp %d\n", *qpn); 67162306a36Sopenharmony_ci if (err) { 67262306a36Sopenharmony_ci en_err(priv, "Failed to reserve qp for mac registration\n"); 67362306a36Sopenharmony_ci mlx4_unregister_mac(dev, priv->port, mac); 67462306a36Sopenharmony_ci return err; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic void mlx4_en_put_qp(struct mlx4_en_priv *priv) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 68362306a36Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 68462306a36Sopenharmony_ci int qpn = priv->base_qpn; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { 68762306a36Sopenharmony_ci u64 mac = ether_addr_to_u64(priv->dev->dev_addr); 68862306a36Sopenharmony_ci en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", 68962306a36Sopenharmony_ci priv->dev->dev_addr); 69062306a36Sopenharmony_ci mlx4_unregister_mac(dev, priv->port, mac); 69162306a36Sopenharmony_ci } else { 69262306a36Sopenharmony_ci en_dbg(DRV, priv, "Releasing qp: port %d, qpn %d\n", 69362306a36Sopenharmony_ci priv->port, qpn); 69462306a36Sopenharmony_ci mlx4_qp_release_range(dev, qpn, 1); 69562306a36Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_cistatic int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn, 70062306a36Sopenharmony_ci unsigned char *new_mac, unsigned char *prev_mac) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 70362306a36Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 70462306a36Sopenharmony_ci int err = 0; 70562306a36Sopenharmony_ci u64 new_mac_u64 = ether_addr_to_u64(new_mac); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { 70862306a36Sopenharmony_ci struct hlist_head *bucket; 70962306a36Sopenharmony_ci unsigned int mac_hash; 71062306a36Sopenharmony_ci struct mlx4_mac_entry *entry; 71162306a36Sopenharmony_ci struct hlist_node *tmp; 71262306a36Sopenharmony_ci u64 prev_mac_u64 = ether_addr_to_u64(prev_mac); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]]; 71562306a36Sopenharmony_ci hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { 71662306a36Sopenharmony_ci if (ether_addr_equal_64bits(entry->mac, prev_mac)) { 71762306a36Sopenharmony_ci mlx4_en_uc_steer_release(priv, entry->mac, 71862306a36Sopenharmony_ci qpn, entry->reg_id); 71962306a36Sopenharmony_ci mlx4_unregister_mac(dev, priv->port, 72062306a36Sopenharmony_ci prev_mac_u64); 72162306a36Sopenharmony_ci hlist_del_rcu(&entry->hlist); 72262306a36Sopenharmony_ci synchronize_rcu(); 72362306a36Sopenharmony_ci memcpy(entry->mac, new_mac, ETH_ALEN); 72462306a36Sopenharmony_ci entry->reg_id = 0; 72562306a36Sopenharmony_ci mac_hash = new_mac[MLX4_EN_MAC_HASH_IDX]; 72662306a36Sopenharmony_ci hlist_add_head_rcu(&entry->hlist, 72762306a36Sopenharmony_ci &priv->mac_hash[mac_hash]); 72862306a36Sopenharmony_ci mlx4_register_mac(dev, priv->port, new_mac_u64); 72962306a36Sopenharmony_ci err = mlx4_en_uc_steer_add(priv, new_mac, 73062306a36Sopenharmony_ci &qpn, 73162306a36Sopenharmony_ci &entry->reg_id); 73262306a36Sopenharmony_ci if (err) 73362306a36Sopenharmony_ci return err; 73462306a36Sopenharmony_ci if (priv->tunnel_reg_id) { 73562306a36Sopenharmony_ci mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id); 73662306a36Sopenharmony_ci priv->tunnel_reg_id = 0; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci err = mlx4_en_tunnel_steer_add(priv, new_mac, qpn, 73962306a36Sopenharmony_ci &priv->tunnel_reg_id); 74062306a36Sopenharmony_ci return err; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci return -EINVAL; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64); 74762306a36Sopenharmony_ci} 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_cistatic void mlx4_en_update_user_mac(struct mlx4_en_priv *priv, 75062306a36Sopenharmony_ci unsigned char new_mac[ETH_ALEN + 2]) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 75362306a36Sopenharmony_ci int err; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_USER_MAC_EN)) 75662306a36Sopenharmony_ci return; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci err = mlx4_SET_PORT_user_mac(mdev->dev, priv->port, new_mac); 75962306a36Sopenharmony_ci if (err) 76062306a36Sopenharmony_ci en_err(priv, "Failed to pass user MAC(%pM) to Firmware for port %d, with error %d\n", 76162306a36Sopenharmony_ci new_mac, priv->port, err); 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic int mlx4_en_do_set_mac(struct mlx4_en_priv *priv, 76562306a36Sopenharmony_ci unsigned char new_mac[ETH_ALEN + 2]) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci int err = 0; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci if (priv->port_up) { 77062306a36Sopenharmony_ci /* Remove old MAC and insert the new one */ 77162306a36Sopenharmony_ci err = mlx4_en_replace_mac(priv, priv->base_qpn, 77262306a36Sopenharmony_ci new_mac, priv->current_mac); 77362306a36Sopenharmony_ci if (err) 77462306a36Sopenharmony_ci en_err(priv, "Failed changing HW MAC address\n"); 77562306a36Sopenharmony_ci } else 77662306a36Sopenharmony_ci en_dbg(HW, priv, "Port is down while registering mac, exiting...\n"); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (!err) 77962306a36Sopenharmony_ci memcpy(priv->current_mac, new_mac, sizeof(priv->current_mac)); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return err; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic int mlx4_en_set_mac(struct net_device *dev, void *addr) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 78762306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 78862306a36Sopenharmony_ci struct sockaddr *saddr = addr; 78962306a36Sopenharmony_ci unsigned char new_mac[ETH_ALEN + 2]; 79062306a36Sopenharmony_ci int err; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (!is_valid_ether_addr(saddr->sa_data)) 79362306a36Sopenharmony_ci return -EADDRNOTAVAIL; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 79662306a36Sopenharmony_ci memcpy(new_mac, saddr->sa_data, ETH_ALEN); 79762306a36Sopenharmony_ci err = mlx4_en_do_set_mac(priv, new_mac); 79862306a36Sopenharmony_ci if (err) 79962306a36Sopenharmony_ci goto out; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci eth_hw_addr_set(dev, saddr->sa_data); 80262306a36Sopenharmony_ci mlx4_en_update_user_mac(priv, new_mac); 80362306a36Sopenharmony_ciout: 80462306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci return err; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_cistatic void mlx4_en_clear_list(struct net_device *dev) 81062306a36Sopenharmony_ci{ 81162306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 81262306a36Sopenharmony_ci struct mlx4_en_mc_list *tmp, *mc_to_del; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci list_for_each_entry_safe(mc_to_del, tmp, &priv->mc_list, list) { 81562306a36Sopenharmony_ci list_del(&mc_to_del->list); 81662306a36Sopenharmony_ci kfree(mc_to_del); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic void mlx4_en_cache_mclist(struct net_device *dev) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 82362306a36Sopenharmony_ci struct netdev_hw_addr *ha; 82462306a36Sopenharmony_ci struct mlx4_en_mc_list *tmp; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci mlx4_en_clear_list(dev); 82762306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 82862306a36Sopenharmony_ci tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC); 82962306a36Sopenharmony_ci if (!tmp) { 83062306a36Sopenharmony_ci mlx4_en_clear_list(dev); 83162306a36Sopenharmony_ci return; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci memcpy(tmp->addr, ha->addr, ETH_ALEN); 83462306a36Sopenharmony_ci list_add_tail(&tmp->list, &priv->mc_list); 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic void update_mclist_flags(struct mlx4_en_priv *priv, 83962306a36Sopenharmony_ci struct list_head *dst, 84062306a36Sopenharmony_ci struct list_head *src) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci struct mlx4_en_mc_list *dst_tmp, *src_tmp, *new_mc; 84362306a36Sopenharmony_ci bool found; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* Find all the entries that should be removed from dst, 84662306a36Sopenharmony_ci * These are the entries that are not found in src 84762306a36Sopenharmony_ci */ 84862306a36Sopenharmony_ci list_for_each_entry(dst_tmp, dst, list) { 84962306a36Sopenharmony_ci found = false; 85062306a36Sopenharmony_ci list_for_each_entry(src_tmp, src, list) { 85162306a36Sopenharmony_ci if (ether_addr_equal(dst_tmp->addr, src_tmp->addr)) { 85262306a36Sopenharmony_ci found = true; 85362306a36Sopenharmony_ci break; 85462306a36Sopenharmony_ci } 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci if (!found) 85762306a36Sopenharmony_ci dst_tmp->action = MCLIST_REM; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* Add entries that exist in src but not in dst 86162306a36Sopenharmony_ci * mark them as need to add 86262306a36Sopenharmony_ci */ 86362306a36Sopenharmony_ci list_for_each_entry(src_tmp, src, list) { 86462306a36Sopenharmony_ci found = false; 86562306a36Sopenharmony_ci list_for_each_entry(dst_tmp, dst, list) { 86662306a36Sopenharmony_ci if (ether_addr_equal(dst_tmp->addr, src_tmp->addr)) { 86762306a36Sopenharmony_ci dst_tmp->action = MCLIST_NONE; 86862306a36Sopenharmony_ci found = true; 86962306a36Sopenharmony_ci break; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci } 87262306a36Sopenharmony_ci if (!found) { 87362306a36Sopenharmony_ci new_mc = kmemdup(src_tmp, 87462306a36Sopenharmony_ci sizeof(struct mlx4_en_mc_list), 87562306a36Sopenharmony_ci GFP_KERNEL); 87662306a36Sopenharmony_ci if (!new_mc) 87762306a36Sopenharmony_ci return; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci new_mc->action = MCLIST_ADD; 88062306a36Sopenharmony_ci list_add_tail(&new_mc->list, dst); 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic void mlx4_en_set_rx_mode(struct net_device *dev) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (!priv->port_up) 89062306a36Sopenharmony_ci return; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci queue_work(priv->mdev->workqueue, &priv->rx_mode_task); 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv, 89662306a36Sopenharmony_ci struct mlx4_en_dev *mdev) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci int err = 0; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { 90162306a36Sopenharmony_ci if (netif_msg_rx_status(priv)) 90262306a36Sopenharmony_ci en_warn(priv, "Entering promiscuous mode\n"); 90362306a36Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_PROMISC; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci /* Enable promiscouos mode */ 90662306a36Sopenharmony_ci switch (mdev->dev->caps.steering_mode) { 90762306a36Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 90862306a36Sopenharmony_ci err = mlx4_flow_steer_promisc_add(mdev->dev, 90962306a36Sopenharmony_ci priv->port, 91062306a36Sopenharmony_ci priv->base_qpn, 91162306a36Sopenharmony_ci MLX4_FS_ALL_DEFAULT); 91262306a36Sopenharmony_ci if (err) 91362306a36Sopenharmony_ci en_err(priv, "Failed enabling promiscuous mode\n"); 91462306a36Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 91562306a36Sopenharmony_ci break; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci case MLX4_STEERING_MODE_B0: 91862306a36Sopenharmony_ci err = mlx4_unicast_promisc_add(mdev->dev, 91962306a36Sopenharmony_ci priv->base_qpn, 92062306a36Sopenharmony_ci priv->port); 92162306a36Sopenharmony_ci if (err) 92262306a36Sopenharmony_ci en_err(priv, "Failed enabling unicast promiscuous mode\n"); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* Add the default qp number as multicast 92562306a36Sopenharmony_ci * promisc 92662306a36Sopenharmony_ci */ 92762306a36Sopenharmony_ci if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { 92862306a36Sopenharmony_ci err = mlx4_multicast_promisc_add(mdev->dev, 92962306a36Sopenharmony_ci priv->base_qpn, 93062306a36Sopenharmony_ci priv->port); 93162306a36Sopenharmony_ci if (err) 93262306a36Sopenharmony_ci en_err(priv, "Failed enabling multicast promiscuous mode\n"); 93362306a36Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci break; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci case MLX4_STEERING_MODE_A0: 93862306a36Sopenharmony_ci err = mlx4_SET_PORT_qpn_calc(mdev->dev, 93962306a36Sopenharmony_ci priv->port, 94062306a36Sopenharmony_ci priv->base_qpn, 94162306a36Sopenharmony_ci 1); 94262306a36Sopenharmony_ci if (err) 94362306a36Sopenharmony_ci en_err(priv, "Failed enabling promiscuous mode\n"); 94462306a36Sopenharmony_ci break; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* Disable port multicast filter (unconditionally) */ 94862306a36Sopenharmony_ci err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 94962306a36Sopenharmony_ci 0, MLX4_MCAST_DISABLE); 95062306a36Sopenharmony_ci if (err) 95162306a36Sopenharmony_ci en_err(priv, "Failed disabling multicast filter\n"); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cistatic void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv, 95662306a36Sopenharmony_ci struct mlx4_en_dev *mdev) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci int err = 0; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (netif_msg_rx_status(priv)) 96162306a36Sopenharmony_ci en_warn(priv, "Leaving promiscuous mode\n"); 96262306a36Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_PROMISC; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* Disable promiscouos mode */ 96562306a36Sopenharmony_ci switch (mdev->dev->caps.steering_mode) { 96662306a36Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 96762306a36Sopenharmony_ci err = mlx4_flow_steer_promisc_remove(mdev->dev, 96862306a36Sopenharmony_ci priv->port, 96962306a36Sopenharmony_ci MLX4_FS_ALL_DEFAULT); 97062306a36Sopenharmony_ci if (err) 97162306a36Sopenharmony_ci en_err(priv, "Failed disabling promiscuous mode\n"); 97262306a36Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 97362306a36Sopenharmony_ci break; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci case MLX4_STEERING_MODE_B0: 97662306a36Sopenharmony_ci err = mlx4_unicast_promisc_remove(mdev->dev, 97762306a36Sopenharmony_ci priv->base_qpn, 97862306a36Sopenharmony_ci priv->port); 97962306a36Sopenharmony_ci if (err) 98062306a36Sopenharmony_ci en_err(priv, "Failed disabling unicast promiscuous mode\n"); 98162306a36Sopenharmony_ci /* Disable Multicast promisc */ 98262306a36Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 98362306a36Sopenharmony_ci err = mlx4_multicast_promisc_remove(mdev->dev, 98462306a36Sopenharmony_ci priv->base_qpn, 98562306a36Sopenharmony_ci priv->port); 98662306a36Sopenharmony_ci if (err) 98762306a36Sopenharmony_ci en_err(priv, "Failed disabling multicast promiscuous mode\n"); 98862306a36Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci break; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci case MLX4_STEERING_MODE_A0: 99362306a36Sopenharmony_ci err = mlx4_SET_PORT_qpn_calc(mdev->dev, 99462306a36Sopenharmony_ci priv->port, 99562306a36Sopenharmony_ci priv->base_qpn, 0); 99662306a36Sopenharmony_ci if (err) 99762306a36Sopenharmony_ci en_err(priv, "Failed disabling promiscuous mode\n"); 99862306a36Sopenharmony_ci break; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic void mlx4_en_do_multicast(struct mlx4_en_priv *priv, 100362306a36Sopenharmony_ci struct net_device *dev, 100462306a36Sopenharmony_ci struct mlx4_en_dev *mdev) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci struct mlx4_en_mc_list *mclist, *tmp; 100762306a36Sopenharmony_ci u64 mcast_addr = 0; 100862306a36Sopenharmony_ci u8 mc_list[16] = {0}; 100962306a36Sopenharmony_ci int err = 0; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* Enable/disable the multicast filter according to IFF_ALLMULTI */ 101262306a36Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) { 101362306a36Sopenharmony_ci err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 101462306a36Sopenharmony_ci 0, MLX4_MCAST_DISABLE); 101562306a36Sopenharmony_ci if (err) 101662306a36Sopenharmony_ci en_err(priv, "Failed disabling multicast filter\n"); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci /* Add the default qp number as multicast promisc */ 101962306a36Sopenharmony_ci if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { 102062306a36Sopenharmony_ci switch (mdev->dev->caps.steering_mode) { 102162306a36Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 102262306a36Sopenharmony_ci err = mlx4_flow_steer_promisc_add(mdev->dev, 102362306a36Sopenharmony_ci priv->port, 102462306a36Sopenharmony_ci priv->base_qpn, 102562306a36Sopenharmony_ci MLX4_FS_MC_DEFAULT); 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci case MLX4_STEERING_MODE_B0: 102962306a36Sopenharmony_ci err = mlx4_multicast_promisc_add(mdev->dev, 103062306a36Sopenharmony_ci priv->base_qpn, 103162306a36Sopenharmony_ci priv->port); 103262306a36Sopenharmony_ci break; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci case MLX4_STEERING_MODE_A0: 103562306a36Sopenharmony_ci break; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci if (err) 103862306a36Sopenharmony_ci en_err(priv, "Failed entering multicast promisc mode\n"); 103962306a36Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci } else { 104262306a36Sopenharmony_ci /* Disable Multicast promisc */ 104362306a36Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 104462306a36Sopenharmony_ci switch (mdev->dev->caps.steering_mode) { 104562306a36Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 104662306a36Sopenharmony_ci err = mlx4_flow_steer_promisc_remove(mdev->dev, 104762306a36Sopenharmony_ci priv->port, 104862306a36Sopenharmony_ci MLX4_FS_MC_DEFAULT); 104962306a36Sopenharmony_ci break; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci case MLX4_STEERING_MODE_B0: 105262306a36Sopenharmony_ci err = mlx4_multicast_promisc_remove(mdev->dev, 105362306a36Sopenharmony_ci priv->base_qpn, 105462306a36Sopenharmony_ci priv->port); 105562306a36Sopenharmony_ci break; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci case MLX4_STEERING_MODE_A0: 105862306a36Sopenharmony_ci break; 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci if (err) 106162306a36Sopenharmony_ci en_err(priv, "Failed disabling multicast promiscuous mode\n"); 106262306a36Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 106662306a36Sopenharmony_ci 0, MLX4_MCAST_DISABLE); 106762306a36Sopenharmony_ci if (err) 106862306a36Sopenharmony_ci en_err(priv, "Failed disabling multicast filter\n"); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci /* Flush mcast filter and init it with broadcast address */ 107162306a36Sopenharmony_ci mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, 107262306a36Sopenharmony_ci 1, MLX4_MCAST_CONFIG); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci /* Update multicast list - we cache all addresses so they won't 107562306a36Sopenharmony_ci * change while HW is updated holding the command semaphor */ 107662306a36Sopenharmony_ci netif_addr_lock_bh(dev); 107762306a36Sopenharmony_ci mlx4_en_cache_mclist(dev); 107862306a36Sopenharmony_ci netif_addr_unlock_bh(dev); 107962306a36Sopenharmony_ci list_for_each_entry(mclist, &priv->mc_list, list) { 108062306a36Sopenharmony_ci mcast_addr = ether_addr_to_u64(mclist->addr); 108162306a36Sopenharmony_ci mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 108262306a36Sopenharmony_ci mcast_addr, 0, MLX4_MCAST_CONFIG); 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 108562306a36Sopenharmony_ci 0, MLX4_MCAST_ENABLE); 108662306a36Sopenharmony_ci if (err) 108762306a36Sopenharmony_ci en_err(priv, "Failed enabling multicast filter\n"); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci update_mclist_flags(priv, &priv->curr_list, &priv->mc_list); 109062306a36Sopenharmony_ci list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { 109162306a36Sopenharmony_ci if (mclist->action == MCLIST_REM) { 109262306a36Sopenharmony_ci /* detach this address and delete from list */ 109362306a36Sopenharmony_ci memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 109462306a36Sopenharmony_ci mc_list[5] = priv->port; 109562306a36Sopenharmony_ci err = mlx4_multicast_detach(mdev->dev, 109662306a36Sopenharmony_ci priv->rss_map.indir_qp, 109762306a36Sopenharmony_ci mc_list, 109862306a36Sopenharmony_ci MLX4_PROT_ETH, 109962306a36Sopenharmony_ci mclist->reg_id); 110062306a36Sopenharmony_ci if (err) 110162306a36Sopenharmony_ci en_err(priv, "Fail to detach multicast address\n"); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (mclist->tunnel_reg_id) { 110462306a36Sopenharmony_ci err = mlx4_flow_detach(priv->mdev->dev, mclist->tunnel_reg_id); 110562306a36Sopenharmony_ci if (err) 110662306a36Sopenharmony_ci en_err(priv, "Failed to detach multicast address\n"); 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* remove from list */ 111062306a36Sopenharmony_ci list_del(&mclist->list); 111162306a36Sopenharmony_ci kfree(mclist); 111262306a36Sopenharmony_ci } else if (mclist->action == MCLIST_ADD) { 111362306a36Sopenharmony_ci /* attach the address */ 111462306a36Sopenharmony_ci memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 111562306a36Sopenharmony_ci /* needed for B0 steering support */ 111662306a36Sopenharmony_ci mc_list[5] = priv->port; 111762306a36Sopenharmony_ci err = mlx4_multicast_attach(mdev->dev, 111862306a36Sopenharmony_ci priv->rss_map.indir_qp, 111962306a36Sopenharmony_ci mc_list, 112062306a36Sopenharmony_ci priv->port, 0, 112162306a36Sopenharmony_ci MLX4_PROT_ETH, 112262306a36Sopenharmony_ci &mclist->reg_id); 112362306a36Sopenharmony_ci if (err) 112462306a36Sopenharmony_ci en_err(priv, "Fail to attach multicast address\n"); 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci err = mlx4_en_tunnel_steer_add(priv, &mc_list[10], priv->base_qpn, 112762306a36Sopenharmony_ci &mclist->tunnel_reg_id); 112862306a36Sopenharmony_ci if (err) 112962306a36Sopenharmony_ci en_err(priv, "Failed to attach multicast address\n"); 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci} 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_cistatic void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv, 113662306a36Sopenharmony_ci struct net_device *dev, 113762306a36Sopenharmony_ci struct mlx4_en_dev *mdev) 113862306a36Sopenharmony_ci{ 113962306a36Sopenharmony_ci struct netdev_hw_addr *ha; 114062306a36Sopenharmony_ci struct mlx4_mac_entry *entry; 114162306a36Sopenharmony_ci struct hlist_node *tmp; 114262306a36Sopenharmony_ci bool found; 114362306a36Sopenharmony_ci u64 mac; 114462306a36Sopenharmony_ci int err = 0; 114562306a36Sopenharmony_ci struct hlist_head *bucket; 114662306a36Sopenharmony_ci unsigned int i; 114762306a36Sopenharmony_ci int removed = 0; 114862306a36Sopenharmony_ci u32 prev_flags; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* Note that we do not need to protect our mac_hash traversal with rcu, 115162306a36Sopenharmony_ci * since all modification code is protected by mdev->state_lock 115262306a36Sopenharmony_ci */ 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci /* find what to remove */ 115562306a36Sopenharmony_ci for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { 115662306a36Sopenharmony_ci bucket = &priv->mac_hash[i]; 115762306a36Sopenharmony_ci hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { 115862306a36Sopenharmony_ci found = false; 115962306a36Sopenharmony_ci netdev_for_each_uc_addr(ha, dev) { 116062306a36Sopenharmony_ci if (ether_addr_equal_64bits(entry->mac, 116162306a36Sopenharmony_ci ha->addr)) { 116262306a36Sopenharmony_ci found = true; 116362306a36Sopenharmony_ci break; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci /* MAC address of the port is not in uc list */ 116862306a36Sopenharmony_ci if (ether_addr_equal_64bits(entry->mac, 116962306a36Sopenharmony_ci priv->current_mac)) 117062306a36Sopenharmony_ci found = true; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (!found) { 117362306a36Sopenharmony_ci mac = ether_addr_to_u64(entry->mac); 117462306a36Sopenharmony_ci mlx4_en_uc_steer_release(priv, entry->mac, 117562306a36Sopenharmony_ci priv->base_qpn, 117662306a36Sopenharmony_ci entry->reg_id); 117762306a36Sopenharmony_ci mlx4_unregister_mac(mdev->dev, priv->port, mac); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci hlist_del_rcu(&entry->hlist); 118062306a36Sopenharmony_ci kfree_rcu(entry, rcu); 118162306a36Sopenharmony_ci en_dbg(DRV, priv, "Removed MAC %pM on port:%d\n", 118262306a36Sopenharmony_ci entry->mac, priv->port); 118362306a36Sopenharmony_ci ++removed; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci } 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci /* if we didn't remove anything, there is no use in trying to add 118962306a36Sopenharmony_ci * again once we are in a forced promisc mode state 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_ci if ((priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) && 0 == removed) 119262306a36Sopenharmony_ci return; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci prev_flags = priv->flags; 119562306a36Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci /* find what to add */ 119862306a36Sopenharmony_ci netdev_for_each_uc_addr(ha, dev) { 119962306a36Sopenharmony_ci found = false; 120062306a36Sopenharmony_ci bucket = &priv->mac_hash[ha->addr[MLX4_EN_MAC_HASH_IDX]]; 120162306a36Sopenharmony_ci hlist_for_each_entry(entry, bucket, hlist) { 120262306a36Sopenharmony_ci if (ether_addr_equal_64bits(entry->mac, ha->addr)) { 120362306a36Sopenharmony_ci found = true; 120462306a36Sopenharmony_ci break; 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci if (!found) { 120962306a36Sopenharmony_ci entry = kmalloc(sizeof(*entry), GFP_KERNEL); 121062306a36Sopenharmony_ci if (!entry) { 121162306a36Sopenharmony_ci en_err(priv, "Failed adding MAC %pM on port:%d (out of memory)\n", 121262306a36Sopenharmony_ci ha->addr, priv->port); 121362306a36Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC; 121462306a36Sopenharmony_ci break; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci mac = ether_addr_to_u64(ha->addr); 121762306a36Sopenharmony_ci memcpy(entry->mac, ha->addr, ETH_ALEN); 121862306a36Sopenharmony_ci err = mlx4_register_mac(mdev->dev, priv->port, mac); 121962306a36Sopenharmony_ci if (err < 0) { 122062306a36Sopenharmony_ci en_err(priv, "Failed registering MAC %pM on port %d: %d\n", 122162306a36Sopenharmony_ci ha->addr, priv->port, err); 122262306a36Sopenharmony_ci kfree(entry); 122362306a36Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC; 122462306a36Sopenharmony_ci break; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci err = mlx4_en_uc_steer_add(priv, ha->addr, 122762306a36Sopenharmony_ci &priv->base_qpn, 122862306a36Sopenharmony_ci &entry->reg_id); 122962306a36Sopenharmony_ci if (err) { 123062306a36Sopenharmony_ci en_err(priv, "Failed adding MAC %pM on port %d: %d\n", 123162306a36Sopenharmony_ci ha->addr, priv->port, err); 123262306a36Sopenharmony_ci mlx4_unregister_mac(mdev->dev, priv->port, mac); 123362306a36Sopenharmony_ci kfree(entry); 123462306a36Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC; 123562306a36Sopenharmony_ci break; 123662306a36Sopenharmony_ci } else { 123762306a36Sopenharmony_ci unsigned int mac_hash; 123862306a36Sopenharmony_ci en_dbg(DRV, priv, "Added MAC %pM on port:%d\n", 123962306a36Sopenharmony_ci ha->addr, priv->port); 124062306a36Sopenharmony_ci mac_hash = ha->addr[MLX4_EN_MAC_HASH_IDX]; 124162306a36Sopenharmony_ci bucket = &priv->mac_hash[mac_hash]; 124262306a36Sopenharmony_ci hlist_add_head_rcu(&entry->hlist, bucket); 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) { 124862306a36Sopenharmony_ci en_warn(priv, "Forcing promiscuous mode on port:%d\n", 124962306a36Sopenharmony_ci priv->port); 125062306a36Sopenharmony_ci } else if (prev_flags & MLX4_EN_FLAG_FORCE_PROMISC) { 125162306a36Sopenharmony_ci en_warn(priv, "Stop forcing promiscuous mode on port:%d\n", 125262306a36Sopenharmony_ci priv->port); 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci} 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic void mlx4_en_do_set_rx_mode(struct work_struct *work) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 125962306a36Sopenharmony_ci rx_mode_task); 126062306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 126162306a36Sopenharmony_ci struct net_device *dev = priv->dev; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 126462306a36Sopenharmony_ci if (!mdev->device_up) { 126562306a36Sopenharmony_ci en_dbg(HW, priv, "Card is not up, ignoring rx mode change.\n"); 126662306a36Sopenharmony_ci goto out; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci if (!priv->port_up) { 126962306a36Sopenharmony_ci en_dbg(HW, priv, "Port is down, ignoring rx mode change.\n"); 127062306a36Sopenharmony_ci goto out; 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (!netif_carrier_ok(dev)) { 127462306a36Sopenharmony_ci if (!mlx4_en_QUERY_PORT(mdev, priv->port)) { 127562306a36Sopenharmony_ci if (priv->port_state.link_state) { 127662306a36Sopenharmony_ci netif_carrier_on(dev); 127762306a36Sopenharmony_ci en_dbg(LINK, priv, "Link Up\n"); 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci if (dev->priv_flags & IFF_UNICAST_FLT) 128362306a36Sopenharmony_ci mlx4_en_do_uc_filter(priv, dev, mdev); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci /* Promsicuous mode: disable all filters */ 128662306a36Sopenharmony_ci if ((dev->flags & IFF_PROMISC) || 128762306a36Sopenharmony_ci (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) { 128862306a36Sopenharmony_ci mlx4_en_set_promisc_mode(priv, mdev); 128962306a36Sopenharmony_ci goto out; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* Not in promiscuous mode */ 129362306a36Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_PROMISC) 129462306a36Sopenharmony_ci mlx4_en_clear_promisc_mode(priv, mdev); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci mlx4_en_do_multicast(priv, dev, mdev); 129762306a36Sopenharmony_ciout: 129862306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_cistatic int mlx4_en_set_rss_steer_rules(struct mlx4_en_priv *priv) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci u64 reg_id; 130462306a36Sopenharmony_ci int err = 0; 130562306a36Sopenharmony_ci int *qpn = &priv->base_qpn; 130662306a36Sopenharmony_ci struct mlx4_mac_entry *entry; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci err = mlx4_en_uc_steer_add(priv, priv->dev->dev_addr, qpn, ®_id); 130962306a36Sopenharmony_ci if (err) 131062306a36Sopenharmony_ci return err; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci err = mlx4_en_tunnel_steer_add(priv, priv->dev->dev_addr, *qpn, 131362306a36Sopenharmony_ci &priv->tunnel_reg_id); 131462306a36Sopenharmony_ci if (err) 131562306a36Sopenharmony_ci goto tunnel_err; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci entry = kmalloc(sizeof(*entry), GFP_KERNEL); 131862306a36Sopenharmony_ci if (!entry) { 131962306a36Sopenharmony_ci err = -ENOMEM; 132062306a36Sopenharmony_ci goto alloc_err; 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac)); 132462306a36Sopenharmony_ci memcpy(priv->current_mac, entry->mac, sizeof(priv->current_mac)); 132562306a36Sopenharmony_ci entry->reg_id = reg_id; 132662306a36Sopenharmony_ci hlist_add_head_rcu(&entry->hlist, 132762306a36Sopenharmony_ci &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci return 0; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cialloc_err: 133262306a36Sopenharmony_ci if (priv->tunnel_reg_id) 133362306a36Sopenharmony_ci mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_citunnel_err: 133662306a36Sopenharmony_ci mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id); 133762306a36Sopenharmony_ci return err; 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic void mlx4_en_delete_rss_steer_rules(struct mlx4_en_priv *priv) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci u64 mac; 134362306a36Sopenharmony_ci unsigned int i; 134462306a36Sopenharmony_ci int qpn = priv->base_qpn; 134562306a36Sopenharmony_ci struct hlist_head *bucket; 134662306a36Sopenharmony_ci struct hlist_node *tmp; 134762306a36Sopenharmony_ci struct mlx4_mac_entry *entry; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { 135062306a36Sopenharmony_ci bucket = &priv->mac_hash[i]; 135162306a36Sopenharmony_ci hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { 135262306a36Sopenharmony_ci mac = ether_addr_to_u64(entry->mac); 135362306a36Sopenharmony_ci en_dbg(DRV, priv, "Registering MAC:%pM for deleting\n", 135462306a36Sopenharmony_ci entry->mac); 135562306a36Sopenharmony_ci mlx4_en_uc_steer_release(priv, entry->mac, 135662306a36Sopenharmony_ci qpn, entry->reg_id); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci mlx4_unregister_mac(priv->mdev->dev, priv->port, mac); 135962306a36Sopenharmony_ci hlist_del_rcu(&entry->hlist); 136062306a36Sopenharmony_ci kfree_rcu(entry, rcu); 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci if (priv->tunnel_reg_id) { 136562306a36Sopenharmony_ci mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id); 136662306a36Sopenharmony_ci priv->tunnel_reg_id = 0; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci} 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_cistatic void mlx4_en_tx_timeout(struct net_device *dev, unsigned int txqueue) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 137362306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 137462306a36Sopenharmony_ci struct mlx4_en_tx_ring *tx_ring = priv->tx_ring[TX][txqueue]; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (netif_msg_timer(priv)) 137762306a36Sopenharmony_ci en_warn(priv, "Tx timeout called on port:%d\n", priv->port); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci en_warn(priv, "TX timeout on queue: %d, QP: 0x%x, CQ: 0x%x, Cons: 0x%x, Prod: 0x%x\n", 138062306a36Sopenharmony_ci txqueue, tx_ring->qpn, tx_ring->sp_cqn, 138162306a36Sopenharmony_ci tx_ring->cons, tx_ring->prod); 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci priv->port_stats.tx_timeout++; 138462306a36Sopenharmony_ci if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state)) { 138562306a36Sopenharmony_ci en_dbg(DRV, priv, "Scheduling port restart\n"); 138662306a36Sopenharmony_ci queue_work(mdev->workqueue, &priv->restart_task); 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci} 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistatic void 139262306a36Sopenharmony_cimlx4_en_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci spin_lock_bh(&priv->stats_lock); 139762306a36Sopenharmony_ci mlx4_en_fold_software_stats(dev); 139862306a36Sopenharmony_ci netdev_stats_to_stats64(stats, &dev->stats); 139962306a36Sopenharmony_ci spin_unlock_bh(&priv->stats_lock); 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) 140362306a36Sopenharmony_ci{ 140462306a36Sopenharmony_ci struct mlx4_en_cq *cq; 140562306a36Sopenharmony_ci int i, t; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* If we haven't received a specific coalescing setting 140862306a36Sopenharmony_ci * (module param), we set the moderation parameters as follows: 140962306a36Sopenharmony_ci * - moder_cnt is set to the number of mtu sized packets to 141062306a36Sopenharmony_ci * satisfy our coalescing target. 141162306a36Sopenharmony_ci * - moder_time is set to a fixed value. 141262306a36Sopenharmony_ci */ 141362306a36Sopenharmony_ci priv->rx_frames = MLX4_EN_RX_COAL_TARGET; 141462306a36Sopenharmony_ci priv->rx_usecs = MLX4_EN_RX_COAL_TIME; 141562306a36Sopenharmony_ci priv->tx_frames = MLX4_EN_TX_COAL_PKTS; 141662306a36Sopenharmony_ci priv->tx_usecs = MLX4_EN_TX_COAL_TIME; 141762306a36Sopenharmony_ci en_dbg(INTR, priv, "Default coalescing params for mtu:%d - rx_frames:%d rx_usecs:%d\n", 141862306a36Sopenharmony_ci priv->dev->mtu, priv->rx_frames, priv->rx_usecs); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci /* Setup cq moderation params */ 142162306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 142262306a36Sopenharmony_ci cq = priv->rx_cq[i]; 142362306a36Sopenharmony_ci cq->moder_cnt = priv->rx_frames; 142462306a36Sopenharmony_ci cq->moder_time = priv->rx_usecs; 142562306a36Sopenharmony_ci priv->last_moder_time[i] = MLX4_EN_AUTO_CONF; 142662306a36Sopenharmony_ci priv->last_moder_packets[i] = 0; 142762306a36Sopenharmony_ci priv->last_moder_bytes[i] = 0; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci for (t = 0 ; t < MLX4_EN_NUM_TX_TYPES; t++) { 143162306a36Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 143262306a36Sopenharmony_ci cq = priv->tx_cq[t][i]; 143362306a36Sopenharmony_ci cq->moder_cnt = priv->tx_frames; 143462306a36Sopenharmony_ci cq->moder_time = priv->tx_usecs; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci /* Reset auto-moderation params */ 143962306a36Sopenharmony_ci priv->pkt_rate_low = MLX4_EN_RX_RATE_LOW; 144062306a36Sopenharmony_ci priv->rx_usecs_low = MLX4_EN_RX_COAL_TIME_LOW; 144162306a36Sopenharmony_ci priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH; 144262306a36Sopenharmony_ci priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH; 144362306a36Sopenharmony_ci priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL; 144462306a36Sopenharmony_ci priv->adaptive_rx_coal = 1; 144562306a36Sopenharmony_ci priv->last_moder_jiffies = 0; 144662306a36Sopenharmony_ci priv->last_moder_tx_packets = 0; 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_cistatic void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) 145062306a36Sopenharmony_ci{ 145162306a36Sopenharmony_ci unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); 145262306a36Sopenharmony_ci u32 pkt_rate_high, pkt_rate_low; 145362306a36Sopenharmony_ci struct mlx4_en_cq *cq; 145462306a36Sopenharmony_ci unsigned long packets; 145562306a36Sopenharmony_ci unsigned long rate; 145662306a36Sopenharmony_ci unsigned long avg_pkt_size; 145762306a36Sopenharmony_ci unsigned long rx_packets; 145862306a36Sopenharmony_ci unsigned long rx_bytes; 145962306a36Sopenharmony_ci unsigned long rx_pkt_diff; 146062306a36Sopenharmony_ci int moder_time; 146162306a36Sopenharmony_ci int ring, err; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ) 146462306a36Sopenharmony_ci return; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci pkt_rate_low = READ_ONCE(priv->pkt_rate_low); 146762306a36Sopenharmony_ci pkt_rate_high = READ_ONCE(priv->pkt_rate_high); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci for (ring = 0; ring < priv->rx_ring_num; ring++) { 147062306a36Sopenharmony_ci rx_packets = READ_ONCE(priv->rx_ring[ring]->packets); 147162306a36Sopenharmony_ci rx_bytes = READ_ONCE(priv->rx_ring[ring]->bytes); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci rx_pkt_diff = rx_packets - priv->last_moder_packets[ring]; 147462306a36Sopenharmony_ci packets = rx_pkt_diff; 147562306a36Sopenharmony_ci rate = packets * HZ / period; 147662306a36Sopenharmony_ci avg_pkt_size = packets ? (rx_bytes - 147762306a36Sopenharmony_ci priv->last_moder_bytes[ring]) / packets : 0; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci /* Apply auto-moderation only when packet rate 148062306a36Sopenharmony_ci * exceeds a rate that it matters */ 148162306a36Sopenharmony_ci if (rate > (MLX4_EN_RX_RATE_THRESH / priv->rx_ring_num) && 148262306a36Sopenharmony_ci avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) { 148362306a36Sopenharmony_ci if (rate <= pkt_rate_low) 148462306a36Sopenharmony_ci moder_time = priv->rx_usecs_low; 148562306a36Sopenharmony_ci else if (rate >= pkt_rate_high) 148662306a36Sopenharmony_ci moder_time = priv->rx_usecs_high; 148762306a36Sopenharmony_ci else 148862306a36Sopenharmony_ci moder_time = (rate - pkt_rate_low) * 148962306a36Sopenharmony_ci (priv->rx_usecs_high - priv->rx_usecs_low) / 149062306a36Sopenharmony_ci (pkt_rate_high - pkt_rate_low) + 149162306a36Sopenharmony_ci priv->rx_usecs_low; 149262306a36Sopenharmony_ci } else { 149362306a36Sopenharmony_ci moder_time = priv->rx_usecs_low; 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci cq = priv->rx_cq[ring]; 149762306a36Sopenharmony_ci if (moder_time != priv->last_moder_time[ring] || 149862306a36Sopenharmony_ci cq->moder_cnt != priv->rx_frames) { 149962306a36Sopenharmony_ci priv->last_moder_time[ring] = moder_time; 150062306a36Sopenharmony_ci cq->moder_time = moder_time; 150162306a36Sopenharmony_ci cq->moder_cnt = priv->rx_frames; 150262306a36Sopenharmony_ci err = mlx4_en_set_cq_moder(priv, cq); 150362306a36Sopenharmony_ci if (err) 150462306a36Sopenharmony_ci en_err(priv, "Failed modifying moderation for cq:%d\n", 150562306a36Sopenharmony_ci ring); 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci priv->last_moder_packets[ring] = rx_packets; 150862306a36Sopenharmony_ci priv->last_moder_bytes[ring] = rx_bytes; 150962306a36Sopenharmony_ci } 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci priv->last_moder_jiffies = jiffies; 151262306a36Sopenharmony_ci} 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_cistatic void mlx4_en_do_get_stats(struct work_struct *work) 151562306a36Sopenharmony_ci{ 151662306a36Sopenharmony_ci struct delayed_work *delay = to_delayed_work(work); 151762306a36Sopenharmony_ci struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, 151862306a36Sopenharmony_ci stats_task); 151962306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 152062306a36Sopenharmony_ci int err; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 152362306a36Sopenharmony_ci if (mdev->device_up) { 152462306a36Sopenharmony_ci if (priv->port_up) { 152562306a36Sopenharmony_ci err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); 152662306a36Sopenharmony_ci if (err) 152762306a36Sopenharmony_ci en_dbg(HW, priv, "Could not update stats\n"); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci mlx4_en_auto_moderation(priv); 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) { 153562306a36Sopenharmony_ci mlx4_en_do_set_mac(priv, priv->current_mac); 153662306a36Sopenharmony_ci mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci/* mlx4_en_service_task - Run service task for tasks that needed to be done 154262306a36Sopenharmony_ci * periodically 154362306a36Sopenharmony_ci */ 154462306a36Sopenharmony_cistatic void mlx4_en_service_task(struct work_struct *work) 154562306a36Sopenharmony_ci{ 154662306a36Sopenharmony_ci struct delayed_work *delay = to_delayed_work(work); 154762306a36Sopenharmony_ci struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, 154862306a36Sopenharmony_ci service_task); 154962306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 155262306a36Sopenharmony_ci if (mdev->device_up) { 155362306a36Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) 155462306a36Sopenharmony_ci mlx4_en_ptp_overflow_check(mdev); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci mlx4_en_recover_from_oom(priv); 155762306a36Sopenharmony_ci queue_delayed_work(mdev->workqueue, &priv->service_task, 155862306a36Sopenharmony_ci SERVICE_TASK_DELAY); 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic void mlx4_en_linkstate(struct mlx4_en_priv *priv) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci struct mlx4_en_port_state *port_state = &priv->port_state; 156662306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 156762306a36Sopenharmony_ci struct net_device *dev = priv->dev; 156862306a36Sopenharmony_ci bool up; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci if (mlx4_en_QUERY_PORT(mdev, priv->port)) 157162306a36Sopenharmony_ci port_state->link_state = MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci up = port_state->link_state == MLX4_PORT_STATE_DEV_EVENT_PORT_UP; 157462306a36Sopenharmony_ci if (up == netif_carrier_ok(dev)) 157562306a36Sopenharmony_ci netif_carrier_event(dev); 157662306a36Sopenharmony_ci if (!up) { 157762306a36Sopenharmony_ci en_info(priv, "Link Down\n"); 157862306a36Sopenharmony_ci netif_carrier_off(dev); 157962306a36Sopenharmony_ci } else { 158062306a36Sopenharmony_ci en_info(priv, "Link Up\n"); 158162306a36Sopenharmony_ci netif_carrier_on(dev); 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci} 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_cistatic void mlx4_en_linkstate_work(struct work_struct *work) 158662306a36Sopenharmony_ci{ 158762306a36Sopenharmony_ci struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 158862306a36Sopenharmony_ci linkstate_task); 158962306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 159262306a36Sopenharmony_ci mlx4_en_linkstate(priv); 159362306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 159462306a36Sopenharmony_ci} 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_cistatic int mlx4_en_init_affinity_hint(struct mlx4_en_priv *priv, int ring_idx) 159762306a36Sopenharmony_ci{ 159862306a36Sopenharmony_ci struct mlx4_en_rx_ring *ring = priv->rx_ring[ring_idx]; 159962306a36Sopenharmony_ci int numa_node = priv->mdev->dev->numa_node; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (!zalloc_cpumask_var(&ring->affinity_mask, GFP_KERNEL)) 160262306a36Sopenharmony_ci return -ENOMEM; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci cpumask_set_cpu(cpumask_local_spread(ring_idx, numa_node), 160562306a36Sopenharmony_ci ring->affinity_mask); 160662306a36Sopenharmony_ci return 0; 160762306a36Sopenharmony_ci} 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_cistatic void mlx4_en_free_affinity_hint(struct mlx4_en_priv *priv, int ring_idx) 161062306a36Sopenharmony_ci{ 161162306a36Sopenharmony_ci free_cpumask_var(priv->rx_ring[ring_idx]->affinity_mask); 161262306a36Sopenharmony_ci} 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_cistatic void mlx4_en_init_recycle_ring(struct mlx4_en_priv *priv, 161562306a36Sopenharmony_ci int tx_ring_idx) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci struct mlx4_en_tx_ring *tx_ring = priv->tx_ring[TX_XDP][tx_ring_idx]; 161862306a36Sopenharmony_ci int rr_index = tx_ring_idx; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci tx_ring->free_tx_desc = mlx4_en_recycle_tx_desc; 162162306a36Sopenharmony_ci tx_ring->recycle_ring = priv->rx_ring[rr_index]; 162262306a36Sopenharmony_ci en_dbg(DRV, priv, "Set tx_ring[%d][%d]->recycle_ring = rx_ring[%d]\n", 162362306a36Sopenharmony_ci TX_XDP, tx_ring_idx, rr_index); 162462306a36Sopenharmony_ci} 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ciint mlx4_en_start_port(struct net_device *dev) 162762306a36Sopenharmony_ci{ 162862306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 162962306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 163062306a36Sopenharmony_ci struct mlx4_en_cq *cq; 163162306a36Sopenharmony_ci struct mlx4_en_tx_ring *tx_ring; 163262306a36Sopenharmony_ci int rx_index = 0; 163362306a36Sopenharmony_ci int err = 0; 163462306a36Sopenharmony_ci int i, t; 163562306a36Sopenharmony_ci int j; 163662306a36Sopenharmony_ci u8 mc_list[16] = {0}; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci if (priv->port_up) { 163962306a36Sopenharmony_ci en_dbg(DRV, priv, "start port called while port already up\n"); 164062306a36Sopenharmony_ci return 0; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->mc_list); 164462306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->curr_list); 164562306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->ethtool_list); 164662306a36Sopenharmony_ci memset(&priv->ethtool_rules[0], 0, 164762306a36Sopenharmony_ci sizeof(struct ethtool_flow_id) * MAX_NUM_OF_FS_RULES); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci /* Calculate Rx buf size */ 165062306a36Sopenharmony_ci dev->mtu = min(dev->mtu, priv->max_mtu); 165162306a36Sopenharmony_ci mlx4_en_calc_rx_buf(dev); 165262306a36Sopenharmony_ci en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci /* Configure rx cq's and rings */ 165562306a36Sopenharmony_ci err = mlx4_en_activate_rx_rings(priv); 165662306a36Sopenharmony_ci if (err) { 165762306a36Sopenharmony_ci en_err(priv, "Failed to activate RX rings\n"); 165862306a36Sopenharmony_ci return err; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 166162306a36Sopenharmony_ci cq = priv->rx_cq[i]; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci err = mlx4_en_init_affinity_hint(priv, i); 166462306a36Sopenharmony_ci if (err) { 166562306a36Sopenharmony_ci en_err(priv, "Failed preparing IRQ affinity hint\n"); 166662306a36Sopenharmony_ci goto cq_err; 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci err = mlx4_en_activate_cq(priv, cq, i); 167062306a36Sopenharmony_ci if (err) { 167162306a36Sopenharmony_ci en_err(priv, "Failed activating Rx CQ\n"); 167262306a36Sopenharmony_ci mlx4_en_free_affinity_hint(priv, i); 167362306a36Sopenharmony_ci goto cq_err; 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci for (j = 0; j < cq->size; j++) { 167762306a36Sopenharmony_ci struct mlx4_cqe *cqe = NULL; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci cqe = mlx4_en_get_cqe(cq->buf, j, priv->cqe_size) + 168062306a36Sopenharmony_ci priv->cqe_factor; 168162306a36Sopenharmony_ci cqe->owner_sr_opcode = MLX4_CQE_OWNER_MASK; 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci err = mlx4_en_set_cq_moder(priv, cq); 168562306a36Sopenharmony_ci if (err) { 168662306a36Sopenharmony_ci en_err(priv, "Failed setting cq moderation parameters\n"); 168762306a36Sopenharmony_ci mlx4_en_deactivate_cq(priv, cq); 168862306a36Sopenharmony_ci mlx4_en_free_affinity_hint(priv, i); 168962306a36Sopenharmony_ci goto cq_err; 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci mlx4_en_arm_cq(priv, cq); 169262306a36Sopenharmony_ci priv->rx_ring[i]->cqn = cq->mcq.cqn; 169362306a36Sopenharmony_ci ++rx_index; 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci /* Set qp number */ 169762306a36Sopenharmony_ci en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port); 169862306a36Sopenharmony_ci err = mlx4_en_get_qp(priv); 169962306a36Sopenharmony_ci if (err) { 170062306a36Sopenharmony_ci en_err(priv, "Failed getting eth qp\n"); 170162306a36Sopenharmony_ci goto cq_err; 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci mdev->mac_removed[priv->port] = 0; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci priv->counter_index = 170662306a36Sopenharmony_ci mlx4_get_default_counter_index(mdev->dev, priv->port); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci err = mlx4_en_config_rss_steer(priv); 170962306a36Sopenharmony_ci if (err) { 171062306a36Sopenharmony_ci en_err(priv, "Failed configuring rss steering\n"); 171162306a36Sopenharmony_ci goto mac_err; 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci err = mlx4_en_create_drop_qp(priv); 171562306a36Sopenharmony_ci if (err) 171662306a36Sopenharmony_ci goto rss_err; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci /* Configure tx cq's and rings */ 171962306a36Sopenharmony_ci for (t = 0 ; t < MLX4_EN_NUM_TX_TYPES; t++) { 172062306a36Sopenharmony_ci u8 num_tx_rings_p_up = t == TX ? 172162306a36Sopenharmony_ci priv->num_tx_rings_p_up : priv->tx_ring_num[t]; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 172462306a36Sopenharmony_ci /* Configure cq */ 172562306a36Sopenharmony_ci cq = priv->tx_cq[t][i]; 172662306a36Sopenharmony_ci err = mlx4_en_activate_cq(priv, cq, i); 172762306a36Sopenharmony_ci if (err) { 172862306a36Sopenharmony_ci en_err(priv, "Failed allocating Tx CQ\n"); 172962306a36Sopenharmony_ci goto tx_err; 173062306a36Sopenharmony_ci } 173162306a36Sopenharmony_ci err = mlx4_en_set_cq_moder(priv, cq); 173262306a36Sopenharmony_ci if (err) { 173362306a36Sopenharmony_ci en_err(priv, "Failed setting cq moderation parameters\n"); 173462306a36Sopenharmony_ci mlx4_en_deactivate_cq(priv, cq); 173562306a36Sopenharmony_ci goto tx_err; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci en_dbg(DRV, priv, 173862306a36Sopenharmony_ci "Resetting index of collapsed CQ:%d to -1\n", i); 173962306a36Sopenharmony_ci cq->buf->wqe_index = cpu_to_be16(0xffff); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci /* Configure ring */ 174262306a36Sopenharmony_ci tx_ring = priv->tx_ring[t][i]; 174362306a36Sopenharmony_ci err = mlx4_en_activate_tx_ring(priv, tx_ring, 174462306a36Sopenharmony_ci cq->mcq.cqn, 174562306a36Sopenharmony_ci i / num_tx_rings_p_up); 174662306a36Sopenharmony_ci if (err) { 174762306a36Sopenharmony_ci en_err(priv, "Failed allocating Tx ring\n"); 174862306a36Sopenharmony_ci mlx4_en_deactivate_cq(priv, cq); 174962306a36Sopenharmony_ci goto tx_err; 175062306a36Sopenharmony_ci } 175162306a36Sopenharmony_ci clear_bit(MLX4_EN_TX_RING_STATE_RECOVERING, &tx_ring->state); 175262306a36Sopenharmony_ci if (t != TX_XDP) { 175362306a36Sopenharmony_ci tx_ring->tx_queue = netdev_get_tx_queue(dev, i); 175462306a36Sopenharmony_ci tx_ring->recycle_ring = NULL; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci /* Arm CQ for TX completions */ 175762306a36Sopenharmony_ci mlx4_en_arm_cq(priv, cq); 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci } else { 176062306a36Sopenharmony_ci mlx4_en_init_tx_xdp_ring_descs(priv, tx_ring); 176162306a36Sopenharmony_ci mlx4_en_init_recycle_ring(priv, i); 176262306a36Sopenharmony_ci /* XDP TX CQ should never be armed */ 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci /* Set initial ownership of all Tx TXBBs to SW (1) */ 176662306a36Sopenharmony_ci for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) 176762306a36Sopenharmony_ci *((u32 *)(tx_ring->buf + j)) = 0xffffffff; 176862306a36Sopenharmony_ci } 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* Configure port */ 177262306a36Sopenharmony_ci err = mlx4_SET_PORT_general(mdev->dev, priv->port, 177362306a36Sopenharmony_ci priv->rx_skb_size + ETH_FCS_LEN, 177462306a36Sopenharmony_ci priv->prof->tx_pause, 177562306a36Sopenharmony_ci priv->prof->tx_ppp, 177662306a36Sopenharmony_ci priv->prof->rx_pause, 177762306a36Sopenharmony_ci priv->prof->rx_ppp); 177862306a36Sopenharmony_ci if (err) { 177962306a36Sopenharmony_ci en_err(priv, "Failed setting port general configurations for port %d, with error %d\n", 178062306a36Sopenharmony_ci priv->port, err); 178162306a36Sopenharmony_ci goto tx_err; 178262306a36Sopenharmony_ci } 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci err = mlx4_SET_PORT_user_mtu(mdev->dev, priv->port, dev->mtu); 178562306a36Sopenharmony_ci if (err) { 178662306a36Sopenharmony_ci en_err(priv, "Failed to pass user MTU(%d) to Firmware for port %d, with error %d\n", 178762306a36Sopenharmony_ci dev->mtu, priv->port, err); 178862306a36Sopenharmony_ci goto tx_err; 178962306a36Sopenharmony_ci } 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci /* Set default qp number */ 179262306a36Sopenharmony_ci err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); 179362306a36Sopenharmony_ci if (err) { 179462306a36Sopenharmony_ci en_err(priv, "Failed setting default qp numbers\n"); 179562306a36Sopenharmony_ci goto tx_err; 179662306a36Sopenharmony_ci } 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) { 179962306a36Sopenharmony_ci err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC, 1); 180062306a36Sopenharmony_ci if (err) { 180162306a36Sopenharmony_ci en_err(priv, "Failed setting port L2 tunnel configuration, err %d\n", 180262306a36Sopenharmony_ci err); 180362306a36Sopenharmony_ci goto tx_err; 180462306a36Sopenharmony_ci } 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci /* Init port */ 180862306a36Sopenharmony_ci en_dbg(HW, priv, "Initializing port\n"); 180962306a36Sopenharmony_ci err = mlx4_INIT_PORT(mdev->dev, priv->port); 181062306a36Sopenharmony_ci if (err) { 181162306a36Sopenharmony_ci en_err(priv, "Failed Initializing port\n"); 181262306a36Sopenharmony_ci goto tx_err; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci /* Set Unicast and VXLAN steering rules */ 181662306a36Sopenharmony_ci if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0 && 181762306a36Sopenharmony_ci mlx4_en_set_rss_steer_rules(priv)) 181862306a36Sopenharmony_ci mlx4_warn(mdev, "Failed setting steering rules\n"); 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci /* Attach rx QP to bradcast address */ 182162306a36Sopenharmony_ci eth_broadcast_addr(&mc_list[10]); 182262306a36Sopenharmony_ci mc_list[5] = priv->port; /* needed for B0 steering support */ 182362306a36Sopenharmony_ci if (mlx4_multicast_attach(mdev->dev, priv->rss_map.indir_qp, mc_list, 182462306a36Sopenharmony_ci priv->port, 0, MLX4_PROT_ETH, 182562306a36Sopenharmony_ci &priv->broadcast_id)) 182662306a36Sopenharmony_ci mlx4_warn(mdev, "Failed Attaching Broadcast\n"); 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci /* Must redo promiscuous mode setup. */ 182962306a36Sopenharmony_ci priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC); 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci /* Schedule multicast task to populate multicast list */ 183262306a36Sopenharmony_ci queue_work(mdev->workqueue, &priv->rx_mode_task); 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci if (priv->mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) 183562306a36Sopenharmony_ci udp_tunnel_nic_reset_ntf(dev); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci priv->port_up = true; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci /* Process all completions if exist to prevent 184062306a36Sopenharmony_ci * the queues freezing if they are full 184162306a36Sopenharmony_ci */ 184262306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 184362306a36Sopenharmony_ci local_bh_disable(); 184462306a36Sopenharmony_ci napi_schedule(&priv->rx_cq[i]->napi); 184562306a36Sopenharmony_ci local_bh_enable(); 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci clear_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state); 184962306a36Sopenharmony_ci netif_tx_start_all_queues(dev); 185062306a36Sopenharmony_ci netif_device_attach(dev); 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci return 0; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_citx_err: 185562306a36Sopenharmony_ci if (t == MLX4_EN_NUM_TX_TYPES) { 185662306a36Sopenharmony_ci t--; 185762306a36Sopenharmony_ci i = priv->tx_ring_num[t]; 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci while (t >= 0) { 186062306a36Sopenharmony_ci while (i--) { 186162306a36Sopenharmony_ci mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[t][i]); 186262306a36Sopenharmony_ci mlx4_en_deactivate_cq(priv, priv->tx_cq[t][i]); 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci if (!t--) 186562306a36Sopenharmony_ci break; 186662306a36Sopenharmony_ci i = priv->tx_ring_num[t]; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci mlx4_en_destroy_drop_qp(priv); 186962306a36Sopenharmony_cirss_err: 187062306a36Sopenharmony_ci mlx4_en_release_rss_steer(priv); 187162306a36Sopenharmony_cimac_err: 187262306a36Sopenharmony_ci mlx4_en_put_qp(priv); 187362306a36Sopenharmony_cicq_err: 187462306a36Sopenharmony_ci while (rx_index--) { 187562306a36Sopenharmony_ci mlx4_en_deactivate_cq(priv, priv->rx_cq[rx_index]); 187662306a36Sopenharmony_ci mlx4_en_free_affinity_hint(priv, rx_index); 187762306a36Sopenharmony_ci } 187862306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) 187962306a36Sopenharmony_ci mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci return err; /* need to close devices */ 188262306a36Sopenharmony_ci} 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_civoid mlx4_en_stop_port(struct net_device *dev, int detach) 188662306a36Sopenharmony_ci{ 188762306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 188862306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 188962306a36Sopenharmony_ci struct mlx4_en_mc_list *mclist, *tmp; 189062306a36Sopenharmony_ci struct ethtool_flow_id *flow, *tmp_flow; 189162306a36Sopenharmony_ci int i, t; 189262306a36Sopenharmony_ci u8 mc_list[16] = {0}; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci if (!priv->port_up) { 189562306a36Sopenharmony_ci en_dbg(DRV, priv, "stop port called while port already down\n"); 189662306a36Sopenharmony_ci return; 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci /* close port*/ 190062306a36Sopenharmony_ci mlx4_CLOSE_PORT(mdev->dev, priv->port); 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci /* Synchronize with tx routine */ 190362306a36Sopenharmony_ci netif_tx_lock_bh(dev); 190462306a36Sopenharmony_ci if (detach) 190562306a36Sopenharmony_ci netif_device_detach(dev); 190662306a36Sopenharmony_ci netif_tx_stop_all_queues(dev); 190762306a36Sopenharmony_ci netif_tx_unlock_bh(dev); 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci netif_tx_disable(dev); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci spin_lock_bh(&priv->stats_lock); 191262306a36Sopenharmony_ci mlx4_en_fold_software_stats(dev); 191362306a36Sopenharmony_ci /* Set port as not active */ 191462306a36Sopenharmony_ci priv->port_up = false; 191562306a36Sopenharmony_ci spin_unlock_bh(&priv->stats_lock); 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci priv->counter_index = MLX4_SINK_COUNTER_INDEX(mdev->dev); 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci /* Promsicuous mode */ 192062306a36Sopenharmony_ci if (mdev->dev->caps.steering_mode == 192162306a36Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED) { 192262306a36Sopenharmony_ci priv->flags &= ~(MLX4_EN_FLAG_PROMISC | 192362306a36Sopenharmony_ci MLX4_EN_FLAG_MC_PROMISC); 192462306a36Sopenharmony_ci mlx4_flow_steer_promisc_remove(mdev->dev, 192562306a36Sopenharmony_ci priv->port, 192662306a36Sopenharmony_ci MLX4_FS_ALL_DEFAULT); 192762306a36Sopenharmony_ci mlx4_flow_steer_promisc_remove(mdev->dev, 192862306a36Sopenharmony_ci priv->port, 192962306a36Sopenharmony_ci MLX4_FS_MC_DEFAULT); 193062306a36Sopenharmony_ci } else if (priv->flags & MLX4_EN_FLAG_PROMISC) { 193162306a36Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_PROMISC; 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci /* Disable promiscouos mode */ 193462306a36Sopenharmony_ci mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, 193562306a36Sopenharmony_ci priv->port); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci /* Disable Multicast promisc */ 193862306a36Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 193962306a36Sopenharmony_ci mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, 194062306a36Sopenharmony_ci priv->port); 194162306a36Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci } 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci /* Detach All multicasts */ 194662306a36Sopenharmony_ci eth_broadcast_addr(&mc_list[10]); 194762306a36Sopenharmony_ci mc_list[5] = priv->port; /* needed for B0 steering support */ 194862306a36Sopenharmony_ci mlx4_multicast_detach(mdev->dev, priv->rss_map.indir_qp, mc_list, 194962306a36Sopenharmony_ci MLX4_PROT_ETH, priv->broadcast_id); 195062306a36Sopenharmony_ci list_for_each_entry(mclist, &priv->curr_list, list) { 195162306a36Sopenharmony_ci memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 195262306a36Sopenharmony_ci mc_list[5] = priv->port; 195362306a36Sopenharmony_ci mlx4_multicast_detach(mdev->dev, priv->rss_map.indir_qp, 195462306a36Sopenharmony_ci mc_list, MLX4_PROT_ETH, mclist->reg_id); 195562306a36Sopenharmony_ci if (mclist->tunnel_reg_id) 195662306a36Sopenharmony_ci mlx4_flow_detach(mdev->dev, mclist->tunnel_reg_id); 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci mlx4_en_clear_list(dev); 195962306a36Sopenharmony_ci list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { 196062306a36Sopenharmony_ci list_del(&mclist->list); 196162306a36Sopenharmony_ci kfree(mclist); 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci /* Flush multicast filter */ 196562306a36Sopenharmony_ci mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci /* Remove flow steering rules for the port*/ 196862306a36Sopenharmony_ci if (mdev->dev->caps.steering_mode == 196962306a36Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED) { 197062306a36Sopenharmony_ci ASSERT_RTNL(); 197162306a36Sopenharmony_ci list_for_each_entry_safe(flow, tmp_flow, 197262306a36Sopenharmony_ci &priv->ethtool_list, list) { 197362306a36Sopenharmony_ci mlx4_flow_detach(mdev->dev, flow->id); 197462306a36Sopenharmony_ci list_del(&flow->list); 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci mlx4_en_destroy_drop_qp(priv); 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci /* Free TX Rings */ 198162306a36Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 198262306a36Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 198362306a36Sopenharmony_ci mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[t][i]); 198462306a36Sopenharmony_ci mlx4_en_deactivate_cq(priv, priv->tx_cq[t][i]); 198562306a36Sopenharmony_ci } 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci msleep(10); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) 199062306a36Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) 199162306a36Sopenharmony_ci mlx4_en_free_tx_buf(dev, priv->tx_ring[t][i]); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 199462306a36Sopenharmony_ci mlx4_en_delete_rss_steer_rules(priv); 199562306a36Sopenharmony_ci 199662306a36Sopenharmony_ci /* Free RSS qps */ 199762306a36Sopenharmony_ci mlx4_en_release_rss_steer(priv); 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci /* Unregister Mac address for the port */ 200062306a36Sopenharmony_ci mlx4_en_put_qp(priv); 200162306a36Sopenharmony_ci if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN)) 200262306a36Sopenharmony_ci mdev->mac_removed[priv->port] = 1; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci /* Free RX Rings */ 200562306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 200662306a36Sopenharmony_ci struct mlx4_en_cq *cq = priv->rx_cq[i]; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci napi_synchronize(&cq->napi); 200962306a36Sopenharmony_ci mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); 201062306a36Sopenharmony_ci mlx4_en_deactivate_cq(priv, cq); 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci mlx4_en_free_affinity_hint(priv, i); 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci} 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_cistatic void mlx4_en_restart(struct work_struct *work) 201762306a36Sopenharmony_ci{ 201862306a36Sopenharmony_ci struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 201962306a36Sopenharmony_ci restart_task); 202062306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 202162306a36Sopenharmony_ci struct net_device *dev = priv->dev; 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci rtnl_lock(); 202662306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 202762306a36Sopenharmony_ci if (priv->port_up) { 202862306a36Sopenharmony_ci mlx4_en_stop_port(dev, 1); 202962306a36Sopenharmony_ci if (mlx4_en_start_port(dev)) 203062306a36Sopenharmony_ci en_err(priv, "Failed restarting port %d\n", priv->port); 203162306a36Sopenharmony_ci } 203262306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 203362306a36Sopenharmony_ci rtnl_unlock(); 203462306a36Sopenharmony_ci} 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_cistatic void mlx4_en_clear_stats(struct net_device *dev) 203762306a36Sopenharmony_ci{ 203862306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 203962306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 204062306a36Sopenharmony_ci struct mlx4_en_tx_ring **tx_ring; 204162306a36Sopenharmony_ci int i; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci if (!mlx4_is_slave(mdev->dev)) 204462306a36Sopenharmony_ci if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) 204562306a36Sopenharmony_ci en_dbg(HW, priv, "Failed dumping statistics\n"); 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci memset(&priv->pkstats, 0, sizeof(priv->pkstats)); 204862306a36Sopenharmony_ci memset(&priv->port_stats, 0, sizeof(priv->port_stats)); 204962306a36Sopenharmony_ci memset(&priv->rx_flowstats, 0, sizeof(priv->rx_flowstats)); 205062306a36Sopenharmony_ci memset(&priv->tx_flowstats, 0, sizeof(priv->tx_flowstats)); 205162306a36Sopenharmony_ci memset(&priv->rx_priority_flowstats, 0, 205262306a36Sopenharmony_ci sizeof(priv->rx_priority_flowstats)); 205362306a36Sopenharmony_ci memset(&priv->tx_priority_flowstats, 0, 205462306a36Sopenharmony_ci sizeof(priv->tx_priority_flowstats)); 205562306a36Sopenharmony_ci memset(&priv->pf_stats, 0, sizeof(priv->pf_stats)); 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci tx_ring = priv->tx_ring[TX]; 205862306a36Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[TX]; i++) { 205962306a36Sopenharmony_ci tx_ring[i]->bytes = 0; 206062306a36Sopenharmony_ci tx_ring[i]->packets = 0; 206162306a36Sopenharmony_ci tx_ring[i]->tx_csum = 0; 206262306a36Sopenharmony_ci tx_ring[i]->tx_dropped = 0; 206362306a36Sopenharmony_ci tx_ring[i]->queue_stopped = 0; 206462306a36Sopenharmony_ci tx_ring[i]->wake_queue = 0; 206562306a36Sopenharmony_ci tx_ring[i]->tso_packets = 0; 206662306a36Sopenharmony_ci tx_ring[i]->xmit_more = 0; 206762306a36Sopenharmony_ci } 206862306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 206962306a36Sopenharmony_ci priv->rx_ring[i]->bytes = 0; 207062306a36Sopenharmony_ci priv->rx_ring[i]->packets = 0; 207162306a36Sopenharmony_ci priv->rx_ring[i]->csum_ok = 0; 207262306a36Sopenharmony_ci priv->rx_ring[i]->csum_none = 0; 207362306a36Sopenharmony_ci priv->rx_ring[i]->csum_complete = 0; 207462306a36Sopenharmony_ci } 207562306a36Sopenharmony_ci} 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_cistatic int mlx4_en_open(struct net_device *dev) 207862306a36Sopenharmony_ci{ 207962306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 208062306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 208162306a36Sopenharmony_ci int err = 0; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci if (!mdev->device_up) { 208662306a36Sopenharmony_ci en_err(priv, "Cannot open - device down/disabled\n"); 208762306a36Sopenharmony_ci err = -EBUSY; 208862306a36Sopenharmony_ci goto out; 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci /* Reset HW statistics and SW counters */ 209262306a36Sopenharmony_ci mlx4_en_clear_stats(dev); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci err = mlx4_en_start_port(dev); 209562306a36Sopenharmony_ci if (err) { 209662306a36Sopenharmony_ci en_err(priv, "Failed starting port:%d\n", priv->port); 209762306a36Sopenharmony_ci goto out; 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci mlx4_en_linkstate(priv); 210062306a36Sopenharmony_ciout: 210162306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 210262306a36Sopenharmony_ci return err; 210362306a36Sopenharmony_ci} 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_cistatic int mlx4_en_close(struct net_device *dev) 210762306a36Sopenharmony_ci{ 210862306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 210962306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci en_dbg(IFDOWN, priv, "Close port called\n"); 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci mlx4_en_stop_port(dev, 0); 211662306a36Sopenharmony_ci netif_carrier_off(dev); 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 211962306a36Sopenharmony_ci return 0; 212062306a36Sopenharmony_ci} 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_cistatic void mlx4_en_free_resources(struct mlx4_en_priv *priv) 212362306a36Sopenharmony_ci{ 212462306a36Sopenharmony_ci int i, t; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 212762306a36Sopenharmony_ci priv->dev->rx_cpu_rmap = NULL; 212862306a36Sopenharmony_ci#endif 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 213162306a36Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 213262306a36Sopenharmony_ci if (priv->tx_ring[t] && priv->tx_ring[t][i]) 213362306a36Sopenharmony_ci mlx4_en_destroy_tx_ring(priv, 213462306a36Sopenharmony_ci &priv->tx_ring[t][i]); 213562306a36Sopenharmony_ci if (priv->tx_cq[t] && priv->tx_cq[t][i]) 213662306a36Sopenharmony_ci mlx4_en_destroy_cq(priv, &priv->tx_cq[t][i]); 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci kfree(priv->tx_ring[t]); 213962306a36Sopenharmony_ci kfree(priv->tx_cq[t]); 214062306a36Sopenharmony_ci } 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 214362306a36Sopenharmony_ci if (priv->rx_ring[i]) 214462306a36Sopenharmony_ci mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], 214562306a36Sopenharmony_ci priv->prof->rx_ring_size, priv->stride); 214662306a36Sopenharmony_ci if (priv->rx_cq[i]) 214762306a36Sopenharmony_ci mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); 214862306a36Sopenharmony_ci } 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci} 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_cistatic int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) 215362306a36Sopenharmony_ci{ 215462306a36Sopenharmony_ci struct mlx4_en_port_profile *prof = priv->prof; 215562306a36Sopenharmony_ci int i, t; 215662306a36Sopenharmony_ci int node; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci /* Create tx Rings */ 215962306a36Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 216062306a36Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 216162306a36Sopenharmony_ci node = cpu_to_node(i % num_online_cpus()); 216262306a36Sopenharmony_ci if (mlx4_en_create_cq(priv, &priv->tx_cq[t][i], 216362306a36Sopenharmony_ci prof->tx_ring_size, i, t, node)) 216462306a36Sopenharmony_ci goto err; 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[t][i], 216762306a36Sopenharmony_ci prof->tx_ring_size, 216862306a36Sopenharmony_ci TXBB_SIZE, node, i)) 216962306a36Sopenharmony_ci goto err; 217062306a36Sopenharmony_ci } 217162306a36Sopenharmony_ci } 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci /* Create rx Rings */ 217462306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 217562306a36Sopenharmony_ci node = cpu_to_node(i % num_online_cpus()); 217662306a36Sopenharmony_ci if (mlx4_en_create_cq(priv, &priv->rx_cq[i], 217762306a36Sopenharmony_ci prof->rx_ring_size, i, RX, node)) 217862306a36Sopenharmony_ci goto err; 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci if (mlx4_en_create_rx_ring(priv, &priv->rx_ring[i], 218162306a36Sopenharmony_ci prof->rx_ring_size, priv->stride, 218262306a36Sopenharmony_ci node, i)) 218362306a36Sopenharmony_ci goto err; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 218862306a36Sopenharmony_ci priv->dev->rx_cpu_rmap = mlx4_get_cpu_rmap(priv->mdev->dev, priv->port); 218962306a36Sopenharmony_ci#endif 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci return 0; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_cierr: 219462306a36Sopenharmony_ci en_err(priv, "Failed to allocate NIC resources\n"); 219562306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 219662306a36Sopenharmony_ci if (priv->rx_ring[i]) 219762306a36Sopenharmony_ci mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], 219862306a36Sopenharmony_ci prof->rx_ring_size, 219962306a36Sopenharmony_ci priv->stride); 220062306a36Sopenharmony_ci if (priv->rx_cq[i]) 220162306a36Sopenharmony_ci mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); 220262306a36Sopenharmony_ci } 220362306a36Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 220462306a36Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 220562306a36Sopenharmony_ci if (priv->tx_ring[t][i]) 220662306a36Sopenharmony_ci mlx4_en_destroy_tx_ring(priv, 220762306a36Sopenharmony_ci &priv->tx_ring[t][i]); 220862306a36Sopenharmony_ci if (priv->tx_cq[t][i]) 220962306a36Sopenharmony_ci mlx4_en_destroy_cq(priv, &priv->tx_cq[t][i]); 221062306a36Sopenharmony_ci } 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci return -ENOMEM; 221362306a36Sopenharmony_ci} 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_cistatic int mlx4_en_copy_priv(struct mlx4_en_priv *dst, 221762306a36Sopenharmony_ci struct mlx4_en_priv *src, 221862306a36Sopenharmony_ci struct mlx4_en_port_profile *prof) 221962306a36Sopenharmony_ci{ 222062306a36Sopenharmony_ci int t; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci memcpy(&dst->hwtstamp_config, &prof->hwtstamp_config, 222362306a36Sopenharmony_ci sizeof(dst->hwtstamp_config)); 222462306a36Sopenharmony_ci dst->num_tx_rings_p_up = prof->num_tx_rings_p_up; 222562306a36Sopenharmony_ci dst->rx_ring_num = prof->rx_ring_num; 222662306a36Sopenharmony_ci dst->flags = prof->flags; 222762306a36Sopenharmony_ci dst->mdev = src->mdev; 222862306a36Sopenharmony_ci dst->port = src->port; 222962306a36Sopenharmony_ci dst->dev = src->dev; 223062306a36Sopenharmony_ci dst->prof = prof; 223162306a36Sopenharmony_ci dst->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + 223262306a36Sopenharmony_ci DS_SIZE * MLX4_EN_MAX_RX_FRAGS); 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 223562306a36Sopenharmony_ci dst->tx_ring_num[t] = prof->tx_ring_num[t]; 223662306a36Sopenharmony_ci if (!dst->tx_ring_num[t]) 223762306a36Sopenharmony_ci continue; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci dst->tx_ring[t] = kcalloc(MAX_TX_RINGS, 224062306a36Sopenharmony_ci sizeof(struct mlx4_en_tx_ring *), 224162306a36Sopenharmony_ci GFP_KERNEL); 224262306a36Sopenharmony_ci if (!dst->tx_ring[t]) 224362306a36Sopenharmony_ci goto err_free_tx; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci dst->tx_cq[t] = kcalloc(MAX_TX_RINGS, 224662306a36Sopenharmony_ci sizeof(struct mlx4_en_cq *), 224762306a36Sopenharmony_ci GFP_KERNEL); 224862306a36Sopenharmony_ci if (!dst->tx_cq[t]) { 224962306a36Sopenharmony_ci kfree(dst->tx_ring[t]); 225062306a36Sopenharmony_ci goto err_free_tx; 225162306a36Sopenharmony_ci } 225262306a36Sopenharmony_ci } 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci return 0; 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_cierr_free_tx: 225762306a36Sopenharmony_ci while (t--) { 225862306a36Sopenharmony_ci kfree(dst->tx_ring[t]); 225962306a36Sopenharmony_ci kfree(dst->tx_cq[t]); 226062306a36Sopenharmony_ci } 226162306a36Sopenharmony_ci return -ENOMEM; 226262306a36Sopenharmony_ci} 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_cistatic void mlx4_en_update_priv(struct mlx4_en_priv *dst, 226562306a36Sopenharmony_ci struct mlx4_en_priv *src) 226662306a36Sopenharmony_ci{ 226762306a36Sopenharmony_ci int t; 226862306a36Sopenharmony_ci memcpy(dst->rx_ring, src->rx_ring, 226962306a36Sopenharmony_ci sizeof(struct mlx4_en_rx_ring *) * src->rx_ring_num); 227062306a36Sopenharmony_ci memcpy(dst->rx_cq, src->rx_cq, 227162306a36Sopenharmony_ci sizeof(struct mlx4_en_cq *) * src->rx_ring_num); 227262306a36Sopenharmony_ci memcpy(&dst->hwtstamp_config, &src->hwtstamp_config, 227362306a36Sopenharmony_ci sizeof(dst->hwtstamp_config)); 227462306a36Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 227562306a36Sopenharmony_ci dst->tx_ring_num[t] = src->tx_ring_num[t]; 227662306a36Sopenharmony_ci dst->tx_ring[t] = src->tx_ring[t]; 227762306a36Sopenharmony_ci dst->tx_cq[t] = src->tx_cq[t]; 227862306a36Sopenharmony_ci } 227962306a36Sopenharmony_ci dst->num_tx_rings_p_up = src->num_tx_rings_p_up; 228062306a36Sopenharmony_ci dst->rx_ring_num = src->rx_ring_num; 228162306a36Sopenharmony_ci memcpy(dst->prof, src->prof, sizeof(struct mlx4_en_port_profile)); 228262306a36Sopenharmony_ci} 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ciint mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv, 228562306a36Sopenharmony_ci struct mlx4_en_priv *tmp, 228662306a36Sopenharmony_ci struct mlx4_en_port_profile *prof, 228762306a36Sopenharmony_ci bool carry_xdp_prog) 228862306a36Sopenharmony_ci{ 228962306a36Sopenharmony_ci struct bpf_prog *xdp_prog; 229062306a36Sopenharmony_ci int i, t, ret; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci ret = mlx4_en_copy_priv(tmp, priv, prof); 229362306a36Sopenharmony_ci if (ret) { 229462306a36Sopenharmony_ci en_warn(priv, "%s: mlx4_en_copy_priv() failed, return\n", 229562306a36Sopenharmony_ci __func__); 229662306a36Sopenharmony_ci return ret; 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci if (mlx4_en_alloc_resources(tmp)) { 230062306a36Sopenharmony_ci en_warn(priv, 230162306a36Sopenharmony_ci "%s: Resource allocation failed, using previous configuration\n", 230262306a36Sopenharmony_ci __func__); 230362306a36Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 230462306a36Sopenharmony_ci kfree(tmp->tx_ring[t]); 230562306a36Sopenharmony_ci kfree(tmp->tx_cq[t]); 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci return -ENOMEM; 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci /* All rx_rings has the same xdp_prog. Pick the first one. */ 231162306a36Sopenharmony_ci xdp_prog = rcu_dereference_protected( 231262306a36Sopenharmony_ci priv->rx_ring[0]->xdp_prog, 231362306a36Sopenharmony_ci lockdep_is_held(&priv->mdev->state_lock)); 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci if (xdp_prog && carry_xdp_prog) { 231662306a36Sopenharmony_ci bpf_prog_add(xdp_prog, tmp->rx_ring_num); 231762306a36Sopenharmony_ci for (i = 0; i < tmp->rx_ring_num; i++) 231862306a36Sopenharmony_ci rcu_assign_pointer(tmp->rx_ring[i]->xdp_prog, 231962306a36Sopenharmony_ci xdp_prog); 232062306a36Sopenharmony_ci } 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci return 0; 232362306a36Sopenharmony_ci} 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_civoid mlx4_en_safe_replace_resources(struct mlx4_en_priv *priv, 232662306a36Sopenharmony_ci struct mlx4_en_priv *tmp) 232762306a36Sopenharmony_ci{ 232862306a36Sopenharmony_ci mlx4_en_free_resources(priv); 232962306a36Sopenharmony_ci mlx4_en_update_priv(priv, tmp); 233062306a36Sopenharmony_ci} 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_civoid mlx4_en_destroy_netdev(struct net_device *dev) 233362306a36Sopenharmony_ci{ 233462306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 233562306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci /* Unregister device - this will close the port if it was up */ 234062306a36Sopenharmony_ci if (priv->registered) 234162306a36Sopenharmony_ci unregister_netdev(dev); 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci if (priv->allocated) 234462306a36Sopenharmony_ci mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE); 234562306a36Sopenharmony_ci 234662306a36Sopenharmony_ci cancel_delayed_work(&priv->stats_task); 234762306a36Sopenharmony_ci cancel_delayed_work(&priv->service_task); 234862306a36Sopenharmony_ci /* flush any pending task for this netdev */ 234962306a36Sopenharmony_ci flush_workqueue(mdev->workqueue); 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) 235262306a36Sopenharmony_ci mlx4_en_remove_timestamp(mdev); 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci /* Detach the netdev so tasks would not attempt to access it */ 235562306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 235662306a36Sopenharmony_ci mdev->pndev[priv->port] = NULL; 235762306a36Sopenharmony_ci mdev->upper[priv->port] = NULL; 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 236062306a36Sopenharmony_ci mlx4_en_cleanup_filters(priv); 236162306a36Sopenharmony_ci#endif 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci mlx4_en_free_resources(priv); 236462306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci free_netdev(dev); 236762306a36Sopenharmony_ci} 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_cistatic bool mlx4_en_check_xdp_mtu(struct net_device *dev, int mtu) 237062306a36Sopenharmony_ci{ 237162306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci if (mtu > MLX4_EN_MAX_XDP_MTU) { 237462306a36Sopenharmony_ci en_err(priv, "mtu:%d > max:%d when XDP prog is attached\n", 237562306a36Sopenharmony_ci mtu, MLX4_EN_MAX_XDP_MTU); 237662306a36Sopenharmony_ci return false; 237762306a36Sopenharmony_ci } 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci return true; 238062306a36Sopenharmony_ci} 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_cistatic int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) 238362306a36Sopenharmony_ci{ 238462306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 238562306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 238662306a36Sopenharmony_ci int err = 0; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci en_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n", 238962306a36Sopenharmony_ci dev->mtu, new_mtu); 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci if (priv->tx_ring_num[TX_XDP] && 239262306a36Sopenharmony_ci !mlx4_en_check_xdp_mtu(dev, new_mtu)) 239362306a36Sopenharmony_ci return -EOPNOTSUPP; 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci dev->mtu = new_mtu; 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci if (netif_running(dev)) { 239862306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 239962306a36Sopenharmony_ci if (!mdev->device_up) { 240062306a36Sopenharmony_ci /* NIC is probably restarting - let restart task reset 240162306a36Sopenharmony_ci * the port */ 240262306a36Sopenharmony_ci en_dbg(DRV, priv, "Change MTU called with card down!?\n"); 240362306a36Sopenharmony_ci } else { 240462306a36Sopenharmony_ci mlx4_en_stop_port(dev, 1); 240562306a36Sopenharmony_ci err = mlx4_en_start_port(dev); 240662306a36Sopenharmony_ci if (err) { 240762306a36Sopenharmony_ci en_err(priv, "Failed restarting port:%d\n", 240862306a36Sopenharmony_ci priv->port); 240962306a36Sopenharmony_ci if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, 241062306a36Sopenharmony_ci &priv->state)) 241162306a36Sopenharmony_ci queue_work(mdev->workqueue, &priv->restart_task); 241262306a36Sopenharmony_ci } 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci return 0; 241762306a36Sopenharmony_ci} 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_cistatic int mlx4_en_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) 242062306a36Sopenharmony_ci{ 242162306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 242262306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 242362306a36Sopenharmony_ci struct hwtstamp_config config; 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 242662306a36Sopenharmony_ci return -EFAULT; 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci /* device doesn't support time stamping */ 242962306a36Sopenharmony_ci if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)) 243062306a36Sopenharmony_ci return -EINVAL; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci /* TX HW timestamp */ 243362306a36Sopenharmony_ci switch (config.tx_type) { 243462306a36Sopenharmony_ci case HWTSTAMP_TX_OFF: 243562306a36Sopenharmony_ci case HWTSTAMP_TX_ON: 243662306a36Sopenharmony_ci break; 243762306a36Sopenharmony_ci default: 243862306a36Sopenharmony_ci return -ERANGE; 243962306a36Sopenharmony_ci } 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci /* RX HW timestamp */ 244262306a36Sopenharmony_ci switch (config.rx_filter) { 244362306a36Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 244462306a36Sopenharmony_ci break; 244562306a36Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 244662306a36Sopenharmony_ci case HWTSTAMP_FILTER_SOME: 244762306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 244862306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 244962306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 245062306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 245162306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 245262306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 245362306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 245462306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 245562306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 245662306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 245762306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_SYNC: 245862306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 245962306a36Sopenharmony_ci case HWTSTAMP_FILTER_NTP_ALL: 246062306a36Sopenharmony_ci config.rx_filter = HWTSTAMP_FILTER_ALL; 246162306a36Sopenharmony_ci break; 246262306a36Sopenharmony_ci default: 246362306a36Sopenharmony_ci return -ERANGE; 246462306a36Sopenharmony_ci } 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci if (mlx4_en_reset_config(dev, config, dev->features)) { 246762306a36Sopenharmony_ci config.tx_type = HWTSTAMP_TX_OFF; 246862306a36Sopenharmony_ci config.rx_filter = HWTSTAMP_FILTER_NONE; 246962306a36Sopenharmony_ci } 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci return copy_to_user(ifr->ifr_data, &config, 247262306a36Sopenharmony_ci sizeof(config)) ? -EFAULT : 0; 247362306a36Sopenharmony_ci} 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_cistatic int mlx4_en_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) 247662306a36Sopenharmony_ci{ 247762306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci return copy_to_user(ifr->ifr_data, &priv->hwtstamp_config, 248062306a36Sopenharmony_ci sizeof(priv->hwtstamp_config)) ? -EFAULT : 0; 248162306a36Sopenharmony_ci} 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_cistatic int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 248462306a36Sopenharmony_ci{ 248562306a36Sopenharmony_ci switch (cmd) { 248662306a36Sopenharmony_ci case SIOCSHWTSTAMP: 248762306a36Sopenharmony_ci return mlx4_en_hwtstamp_set(dev, ifr); 248862306a36Sopenharmony_ci case SIOCGHWTSTAMP: 248962306a36Sopenharmony_ci return mlx4_en_hwtstamp_get(dev, ifr); 249062306a36Sopenharmony_ci default: 249162306a36Sopenharmony_ci return -EOPNOTSUPP; 249262306a36Sopenharmony_ci } 249362306a36Sopenharmony_ci} 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_cistatic netdev_features_t mlx4_en_fix_features(struct net_device *netdev, 249662306a36Sopenharmony_ci netdev_features_t features) 249762306a36Sopenharmony_ci{ 249862306a36Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(netdev); 249962306a36Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci /* Since there is no support for separate RX C-TAG/S-TAG vlan accel 250262306a36Sopenharmony_ci * enable/disable make sure S-TAG flag is always in same state as 250362306a36Sopenharmony_ci * C-TAG. 250462306a36Sopenharmony_ci */ 250562306a36Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX && 250662306a36Sopenharmony_ci !(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) 250762306a36Sopenharmony_ci features |= NETIF_F_HW_VLAN_STAG_RX; 250862306a36Sopenharmony_ci else 250962306a36Sopenharmony_ci features &= ~NETIF_F_HW_VLAN_STAG_RX; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci return features; 251262306a36Sopenharmony_ci} 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_cistatic int mlx4_en_set_features(struct net_device *netdev, 251562306a36Sopenharmony_ci netdev_features_t features) 251662306a36Sopenharmony_ci{ 251762306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(netdev); 251862306a36Sopenharmony_ci bool reset = false; 251962306a36Sopenharmony_ci int ret = 0; 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_RXFCS)) { 252262306a36Sopenharmony_ci en_info(priv, "Turn %s RX-FCS\n", 252362306a36Sopenharmony_ci (features & NETIF_F_RXFCS) ? "ON" : "OFF"); 252462306a36Sopenharmony_ci reset = true; 252562306a36Sopenharmony_ci } 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_RXALL)) { 252862306a36Sopenharmony_ci u8 ignore_fcs_value = (features & NETIF_F_RXALL) ? 1 : 0; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci en_info(priv, "Turn %s RX-ALL\n", 253162306a36Sopenharmony_ci ignore_fcs_value ? "ON" : "OFF"); 253262306a36Sopenharmony_ci ret = mlx4_SET_PORT_fcs_check(priv->mdev->dev, 253362306a36Sopenharmony_ci priv->port, ignore_fcs_value); 253462306a36Sopenharmony_ci if (ret) 253562306a36Sopenharmony_ci return ret; 253662306a36Sopenharmony_ci } 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_RX)) { 253962306a36Sopenharmony_ci en_info(priv, "Turn %s RX vlan strip offload\n", 254062306a36Sopenharmony_ci (features & NETIF_F_HW_VLAN_CTAG_RX) ? "ON" : "OFF"); 254162306a36Sopenharmony_ci reset = true; 254262306a36Sopenharmony_ci } 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_TX)) 254562306a36Sopenharmony_ci en_info(priv, "Turn %s TX vlan strip offload\n", 254662306a36Sopenharmony_ci (features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF"); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_STAG_TX)) 254962306a36Sopenharmony_ci en_info(priv, "Turn %s TX S-VLAN strip offload\n", 255062306a36Sopenharmony_ci (features & NETIF_F_HW_VLAN_STAG_TX) ? "ON" : "OFF"); 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_LOOPBACK)) { 255362306a36Sopenharmony_ci en_info(priv, "Turn %s loopback\n", 255462306a36Sopenharmony_ci (features & NETIF_F_LOOPBACK) ? "ON" : "OFF"); 255562306a36Sopenharmony_ci mlx4_en_update_loopback_state(netdev, features); 255662306a36Sopenharmony_ci } 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci if (reset) { 255962306a36Sopenharmony_ci ret = mlx4_en_reset_config(netdev, priv->hwtstamp_config, 256062306a36Sopenharmony_ci features); 256162306a36Sopenharmony_ci if (ret) 256262306a36Sopenharmony_ci return ret; 256362306a36Sopenharmony_ci } 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci return 0; 256662306a36Sopenharmony_ci} 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_cistatic int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac) 256962306a36Sopenharmony_ci{ 257062306a36Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 257162306a36Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac); 257462306a36Sopenharmony_ci} 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_cistatic int mlx4_en_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos, 257762306a36Sopenharmony_ci __be16 vlan_proto) 257862306a36Sopenharmony_ci{ 257962306a36Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 258062306a36Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci return mlx4_set_vf_vlan(mdev->dev, en_priv->port, vf, vlan, qos, 258362306a36Sopenharmony_ci vlan_proto); 258462306a36Sopenharmony_ci} 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_cistatic int mlx4_en_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate, 258762306a36Sopenharmony_ci int max_tx_rate) 258862306a36Sopenharmony_ci{ 258962306a36Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 259062306a36Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci return mlx4_set_vf_rate(mdev->dev, en_priv->port, vf, min_tx_rate, 259362306a36Sopenharmony_ci max_tx_rate); 259462306a36Sopenharmony_ci} 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_cistatic int mlx4_en_set_vf_spoofchk(struct net_device *dev, int vf, bool setting) 259762306a36Sopenharmony_ci{ 259862306a36Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 259962306a36Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci return mlx4_set_vf_spoofchk(mdev->dev, en_priv->port, vf, setting); 260262306a36Sopenharmony_ci} 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_cistatic int mlx4_en_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivf) 260562306a36Sopenharmony_ci{ 260662306a36Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 260762306a36Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci return mlx4_get_vf_config(mdev->dev, en_priv->port, vf, ivf); 261062306a36Sopenharmony_ci} 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_cistatic int mlx4_en_set_vf_link_state(struct net_device *dev, int vf, int link_state) 261362306a36Sopenharmony_ci{ 261462306a36Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 261562306a36Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci return mlx4_set_vf_link_state(mdev->dev, en_priv->port, vf, link_state); 261862306a36Sopenharmony_ci} 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_cistatic int mlx4_en_get_vf_stats(struct net_device *dev, int vf, 262162306a36Sopenharmony_ci struct ifla_vf_stats *vf_stats) 262262306a36Sopenharmony_ci{ 262362306a36Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 262462306a36Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci return mlx4_get_vf_stats(mdev->dev, en_priv->port, vf, vf_stats); 262762306a36Sopenharmony_ci} 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci#define PORT_ID_BYTE_LEN 8 263062306a36Sopenharmony_cistatic int mlx4_en_get_phys_port_id(struct net_device *dev, 263162306a36Sopenharmony_ci struct netdev_phys_item_id *ppid) 263262306a36Sopenharmony_ci{ 263362306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 263462306a36Sopenharmony_ci struct mlx4_dev *mdev = priv->mdev->dev; 263562306a36Sopenharmony_ci int i; 263662306a36Sopenharmony_ci u64 phys_port_id = mdev->caps.phys_port_id[priv->port]; 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci if (!phys_port_id) 263962306a36Sopenharmony_ci return -EOPNOTSUPP; 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci ppid->id_len = sizeof(phys_port_id); 264262306a36Sopenharmony_ci for (i = PORT_ID_BYTE_LEN - 1; i >= 0; --i) { 264362306a36Sopenharmony_ci ppid->id[i] = phys_port_id & 0xff; 264462306a36Sopenharmony_ci phys_port_id >>= 8; 264562306a36Sopenharmony_ci } 264662306a36Sopenharmony_ci return 0; 264762306a36Sopenharmony_ci} 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_cistatic int mlx4_udp_tunnel_sync(struct net_device *dev, unsigned int table) 265062306a36Sopenharmony_ci{ 265162306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 265262306a36Sopenharmony_ci struct udp_tunnel_info ti; 265362306a36Sopenharmony_ci int ret; 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci udp_tunnel_nic_get_port(dev, table, 0, &ti); 265662306a36Sopenharmony_ci priv->vxlan_port = ti.port; 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci ret = mlx4_config_vxlan_port(priv->mdev->dev, priv->vxlan_port); 265962306a36Sopenharmony_ci if (ret) 266062306a36Sopenharmony_ci return ret; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci return mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port, 266362306a36Sopenharmony_ci VXLAN_STEER_BY_OUTER_MAC, 266462306a36Sopenharmony_ci !!priv->vxlan_port); 266562306a36Sopenharmony_ci} 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_cistatic const struct udp_tunnel_nic_info mlx4_udp_tunnels = { 266862306a36Sopenharmony_ci .sync_table = mlx4_udp_tunnel_sync, 266962306a36Sopenharmony_ci .flags = UDP_TUNNEL_NIC_INFO_MAY_SLEEP | 267062306a36Sopenharmony_ci UDP_TUNNEL_NIC_INFO_IPV4_ONLY, 267162306a36Sopenharmony_ci .tables = { 267262306a36Sopenharmony_ci { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, }, 267362306a36Sopenharmony_ci }, 267462306a36Sopenharmony_ci}; 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_cistatic netdev_features_t mlx4_en_features_check(struct sk_buff *skb, 267762306a36Sopenharmony_ci struct net_device *dev, 267862306a36Sopenharmony_ci netdev_features_t features) 267962306a36Sopenharmony_ci{ 268062306a36Sopenharmony_ci features = vlan_features_check(skb, features); 268162306a36Sopenharmony_ci features = vxlan_features_check(skb, features); 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci /* The ConnectX-3 doesn't support outer IPv6 checksums but it does 268462306a36Sopenharmony_ci * support inner IPv6 checksums and segmentation so we need to 268562306a36Sopenharmony_ci * strip that feature if this is an IPv6 encapsulated frame. 268662306a36Sopenharmony_ci */ 268762306a36Sopenharmony_ci if (skb->encapsulation && 268862306a36Sopenharmony_ci (skb->ip_summed == CHECKSUM_PARTIAL)) { 268962306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci if (!priv->vxlan_port || 269262306a36Sopenharmony_ci (ip_hdr(skb)->version != 4) || 269362306a36Sopenharmony_ci (udp_hdr(skb)->dest != priv->vxlan_port)) 269462306a36Sopenharmony_ci features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); 269562306a36Sopenharmony_ci } 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci return features; 269862306a36Sopenharmony_ci} 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_cistatic int mlx4_en_set_tx_maxrate(struct net_device *dev, int queue_index, u32 maxrate) 270162306a36Sopenharmony_ci{ 270262306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 270362306a36Sopenharmony_ci struct mlx4_en_tx_ring *tx_ring = priv->tx_ring[TX][queue_index]; 270462306a36Sopenharmony_ci struct mlx4_update_qp_params params; 270562306a36Sopenharmony_ci int err; 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT)) 270862306a36Sopenharmony_ci return -EOPNOTSUPP; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci /* rate provided to us in Mbs, check if it fits into 12 bits, if not use Gbs */ 271162306a36Sopenharmony_ci if (maxrate >> 12) { 271262306a36Sopenharmony_ci params.rate_unit = MLX4_QP_RATE_LIMIT_GBS; 271362306a36Sopenharmony_ci params.rate_val = maxrate / 1000; 271462306a36Sopenharmony_ci } else if (maxrate) { 271562306a36Sopenharmony_ci params.rate_unit = MLX4_QP_RATE_LIMIT_MBS; 271662306a36Sopenharmony_ci params.rate_val = maxrate; 271762306a36Sopenharmony_ci } else { /* zero serves to revoke the QP rate-limitation */ 271862306a36Sopenharmony_ci params.rate_unit = 0; 271962306a36Sopenharmony_ci params.rate_val = 0; 272062306a36Sopenharmony_ci } 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci err = mlx4_update_qp(priv->mdev->dev, tx_ring->qpn, MLX4_UPDATE_QP_RATE_LIMIT, 272362306a36Sopenharmony_ci ¶ms); 272462306a36Sopenharmony_ci return err; 272562306a36Sopenharmony_ci} 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_cistatic int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) 272862306a36Sopenharmony_ci{ 272962306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 273062306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 273162306a36Sopenharmony_ci struct mlx4_en_port_profile new_prof; 273262306a36Sopenharmony_ci struct bpf_prog *old_prog; 273362306a36Sopenharmony_ci struct mlx4_en_priv *tmp; 273462306a36Sopenharmony_ci int tx_changed = 0; 273562306a36Sopenharmony_ci int xdp_ring_num; 273662306a36Sopenharmony_ci int port_up = 0; 273762306a36Sopenharmony_ci int err; 273862306a36Sopenharmony_ci int i; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci xdp_ring_num = prog ? priv->rx_ring_num : 0; 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_ci /* No need to reconfigure buffers when simply swapping the 274362306a36Sopenharmony_ci * program for a new one. 274462306a36Sopenharmony_ci */ 274562306a36Sopenharmony_ci if (priv->tx_ring_num[TX_XDP] == xdp_ring_num) { 274662306a36Sopenharmony_ci if (prog) 274762306a36Sopenharmony_ci bpf_prog_add(prog, priv->rx_ring_num - 1); 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 275062306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 275162306a36Sopenharmony_ci old_prog = rcu_dereference_protected( 275262306a36Sopenharmony_ci priv->rx_ring[i]->xdp_prog, 275362306a36Sopenharmony_ci lockdep_is_held(&mdev->state_lock)); 275462306a36Sopenharmony_ci rcu_assign_pointer(priv->rx_ring[i]->xdp_prog, prog); 275562306a36Sopenharmony_ci if (old_prog) 275662306a36Sopenharmony_ci bpf_prog_put(old_prog); 275762306a36Sopenharmony_ci } 275862306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 275962306a36Sopenharmony_ci return 0; 276062306a36Sopenharmony_ci } 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci if (!mlx4_en_check_xdp_mtu(dev, dev->mtu)) 276362306a36Sopenharmony_ci return -EOPNOTSUPP; 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 276662306a36Sopenharmony_ci if (!tmp) 276762306a36Sopenharmony_ci return -ENOMEM; 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci if (prog) 277062306a36Sopenharmony_ci bpf_prog_add(prog, priv->rx_ring_num - 1); 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 277362306a36Sopenharmony_ci memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); 277462306a36Sopenharmony_ci new_prof.tx_ring_num[TX_XDP] = xdp_ring_num; 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci if (priv->tx_ring_num[TX] + xdp_ring_num > MAX_TX_RINGS) { 277762306a36Sopenharmony_ci tx_changed = 1; 277862306a36Sopenharmony_ci new_prof.tx_ring_num[TX] = 277962306a36Sopenharmony_ci MAX_TX_RINGS - ALIGN(xdp_ring_num, priv->prof->num_up); 278062306a36Sopenharmony_ci en_warn(priv, "Reducing the number of TX rings, to not exceed the max total rings number.\n"); 278162306a36Sopenharmony_ci } 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, false); 278462306a36Sopenharmony_ci if (err) { 278562306a36Sopenharmony_ci if (prog) 278662306a36Sopenharmony_ci bpf_prog_sub(prog, priv->rx_ring_num - 1); 278762306a36Sopenharmony_ci goto unlock_out; 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci if (priv->port_up) { 279162306a36Sopenharmony_ci port_up = 1; 279262306a36Sopenharmony_ci mlx4_en_stop_port(dev, 1); 279362306a36Sopenharmony_ci } 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci mlx4_en_safe_replace_resources(priv, tmp); 279662306a36Sopenharmony_ci if (tx_changed) 279762306a36Sopenharmony_ci netif_set_real_num_tx_queues(dev, priv->tx_ring_num[TX]); 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 280062306a36Sopenharmony_ci old_prog = rcu_dereference_protected( 280162306a36Sopenharmony_ci priv->rx_ring[i]->xdp_prog, 280262306a36Sopenharmony_ci lockdep_is_held(&mdev->state_lock)); 280362306a36Sopenharmony_ci rcu_assign_pointer(priv->rx_ring[i]->xdp_prog, prog); 280462306a36Sopenharmony_ci if (old_prog) 280562306a36Sopenharmony_ci bpf_prog_put(old_prog); 280662306a36Sopenharmony_ci } 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci if (port_up) { 280962306a36Sopenharmony_ci err = mlx4_en_start_port(dev); 281062306a36Sopenharmony_ci if (err) { 281162306a36Sopenharmony_ci en_err(priv, "Failed starting port %d for XDP change\n", 281262306a36Sopenharmony_ci priv->port); 281362306a36Sopenharmony_ci if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state)) 281462306a36Sopenharmony_ci queue_work(mdev->workqueue, &priv->restart_task); 281562306a36Sopenharmony_ci } 281662306a36Sopenharmony_ci } 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ciunlock_out: 281962306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 282062306a36Sopenharmony_ci kfree(tmp); 282162306a36Sopenharmony_ci return err; 282262306a36Sopenharmony_ci} 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_cistatic int mlx4_xdp(struct net_device *dev, struct netdev_bpf *xdp) 282562306a36Sopenharmony_ci{ 282662306a36Sopenharmony_ci switch (xdp->command) { 282762306a36Sopenharmony_ci case XDP_SETUP_PROG: 282862306a36Sopenharmony_ci return mlx4_xdp_set(dev, xdp->prog); 282962306a36Sopenharmony_ci default: 283062306a36Sopenharmony_ci return -EINVAL; 283162306a36Sopenharmony_ci } 283262306a36Sopenharmony_ci} 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_cistatic const struct net_device_ops mlx4_netdev_ops = { 283562306a36Sopenharmony_ci .ndo_open = mlx4_en_open, 283662306a36Sopenharmony_ci .ndo_stop = mlx4_en_close, 283762306a36Sopenharmony_ci .ndo_start_xmit = mlx4_en_xmit, 283862306a36Sopenharmony_ci .ndo_select_queue = mlx4_en_select_queue, 283962306a36Sopenharmony_ci .ndo_get_stats64 = mlx4_en_get_stats64, 284062306a36Sopenharmony_ci .ndo_set_rx_mode = mlx4_en_set_rx_mode, 284162306a36Sopenharmony_ci .ndo_set_mac_address = mlx4_en_set_mac, 284262306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 284362306a36Sopenharmony_ci .ndo_change_mtu = mlx4_en_change_mtu, 284462306a36Sopenharmony_ci .ndo_eth_ioctl = mlx4_en_ioctl, 284562306a36Sopenharmony_ci .ndo_tx_timeout = mlx4_en_tx_timeout, 284662306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid, 284762306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, 284862306a36Sopenharmony_ci .ndo_set_features = mlx4_en_set_features, 284962306a36Sopenharmony_ci .ndo_fix_features = mlx4_en_fix_features, 285062306a36Sopenharmony_ci .ndo_setup_tc = __mlx4_en_setup_tc, 285162306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 285262306a36Sopenharmony_ci .ndo_rx_flow_steer = mlx4_en_filter_rfs, 285362306a36Sopenharmony_ci#endif 285462306a36Sopenharmony_ci .ndo_get_phys_port_id = mlx4_en_get_phys_port_id, 285562306a36Sopenharmony_ci .ndo_features_check = mlx4_en_features_check, 285662306a36Sopenharmony_ci .ndo_set_tx_maxrate = mlx4_en_set_tx_maxrate, 285762306a36Sopenharmony_ci .ndo_bpf = mlx4_xdp, 285862306a36Sopenharmony_ci}; 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_cistatic const struct net_device_ops mlx4_netdev_ops_master = { 286162306a36Sopenharmony_ci .ndo_open = mlx4_en_open, 286262306a36Sopenharmony_ci .ndo_stop = mlx4_en_close, 286362306a36Sopenharmony_ci .ndo_start_xmit = mlx4_en_xmit, 286462306a36Sopenharmony_ci .ndo_select_queue = mlx4_en_select_queue, 286562306a36Sopenharmony_ci .ndo_get_stats64 = mlx4_en_get_stats64, 286662306a36Sopenharmony_ci .ndo_set_rx_mode = mlx4_en_set_rx_mode, 286762306a36Sopenharmony_ci .ndo_set_mac_address = mlx4_en_set_mac, 286862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 286962306a36Sopenharmony_ci .ndo_change_mtu = mlx4_en_change_mtu, 287062306a36Sopenharmony_ci .ndo_tx_timeout = mlx4_en_tx_timeout, 287162306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid, 287262306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, 287362306a36Sopenharmony_ci .ndo_set_vf_mac = mlx4_en_set_vf_mac, 287462306a36Sopenharmony_ci .ndo_set_vf_vlan = mlx4_en_set_vf_vlan, 287562306a36Sopenharmony_ci .ndo_set_vf_rate = mlx4_en_set_vf_rate, 287662306a36Sopenharmony_ci .ndo_set_vf_spoofchk = mlx4_en_set_vf_spoofchk, 287762306a36Sopenharmony_ci .ndo_set_vf_link_state = mlx4_en_set_vf_link_state, 287862306a36Sopenharmony_ci .ndo_get_vf_stats = mlx4_en_get_vf_stats, 287962306a36Sopenharmony_ci .ndo_get_vf_config = mlx4_en_get_vf_config, 288062306a36Sopenharmony_ci .ndo_set_features = mlx4_en_set_features, 288162306a36Sopenharmony_ci .ndo_fix_features = mlx4_en_fix_features, 288262306a36Sopenharmony_ci .ndo_setup_tc = __mlx4_en_setup_tc, 288362306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 288462306a36Sopenharmony_ci .ndo_rx_flow_steer = mlx4_en_filter_rfs, 288562306a36Sopenharmony_ci#endif 288662306a36Sopenharmony_ci .ndo_get_phys_port_id = mlx4_en_get_phys_port_id, 288762306a36Sopenharmony_ci .ndo_features_check = mlx4_en_features_check, 288862306a36Sopenharmony_ci .ndo_set_tx_maxrate = mlx4_en_set_tx_maxrate, 288962306a36Sopenharmony_ci .ndo_bpf = mlx4_xdp, 289062306a36Sopenharmony_ci}; 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_cistatic const struct xdp_metadata_ops mlx4_xdp_metadata_ops = { 289362306a36Sopenharmony_ci .xmo_rx_timestamp = mlx4_en_xdp_rx_timestamp, 289462306a36Sopenharmony_ci .xmo_rx_hash = mlx4_en_xdp_rx_hash, 289562306a36Sopenharmony_ci}; 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ciint mlx4_en_netdev_event(struct notifier_block *this, 289862306a36Sopenharmony_ci unsigned long event, void *ptr) 289962306a36Sopenharmony_ci{ 290062306a36Sopenharmony_ci struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 290162306a36Sopenharmony_ci u8 port = 0; 290262306a36Sopenharmony_ci struct mlx4_en_dev *mdev; 290362306a36Sopenharmony_ci struct mlx4_dev *dev; 290462306a36Sopenharmony_ci int i, num_eth_ports = 0; 290562306a36Sopenharmony_ci bool do_bond = true; 290662306a36Sopenharmony_ci u8 v2p_port1 = 0; 290762306a36Sopenharmony_ci u8 v2p_port2 = 0; 290862306a36Sopenharmony_ci 290962306a36Sopenharmony_ci if (!net_eq(dev_net(ndev), &init_net)) 291062306a36Sopenharmony_ci return NOTIFY_DONE; 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci mdev = container_of(this, struct mlx4_en_dev, netdev_nb); 291362306a36Sopenharmony_ci dev = mdev->dev; 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci /* Go into this mode only when two network devices set on two ports 291662306a36Sopenharmony_ci * of the same mlx4 device are slaves of the same bonding master 291762306a36Sopenharmony_ci */ 291862306a36Sopenharmony_ci mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { 291962306a36Sopenharmony_ci ++num_eth_ports; 292062306a36Sopenharmony_ci if (!port && (mdev->pndev[i] == ndev)) 292162306a36Sopenharmony_ci port = i; 292262306a36Sopenharmony_ci mdev->upper[i] = mdev->pndev[i] ? 292362306a36Sopenharmony_ci netdev_master_upper_dev_get(mdev->pndev[i]) : NULL; 292462306a36Sopenharmony_ci /* condition not met: network device is a slave */ 292562306a36Sopenharmony_ci if (!mdev->upper[i]) 292662306a36Sopenharmony_ci do_bond = false; 292762306a36Sopenharmony_ci if (num_eth_ports < 2) 292862306a36Sopenharmony_ci continue; 292962306a36Sopenharmony_ci /* condition not met: same master */ 293062306a36Sopenharmony_ci if (mdev->upper[i] != mdev->upper[i-1]) 293162306a36Sopenharmony_ci do_bond = false; 293262306a36Sopenharmony_ci } 293362306a36Sopenharmony_ci /* condition not met: 2 salves */ 293462306a36Sopenharmony_ci do_bond = (num_eth_ports == 2) ? do_bond : false; 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci /* handle only events that come with enough info */ 293762306a36Sopenharmony_ci if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port) 293862306a36Sopenharmony_ci return NOTIFY_DONE; 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci if (do_bond) { 294162306a36Sopenharmony_ci struct netdev_notifier_bonding_info *notifier_info = ptr; 294262306a36Sopenharmony_ci struct netdev_bonding_info *bonding_info = 294362306a36Sopenharmony_ci ¬ifier_info->bonding_info; 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_ci /* required mode 1, 2 or 4 */ 294662306a36Sopenharmony_ci if ((bonding_info->master.bond_mode != BOND_MODE_ACTIVEBACKUP) && 294762306a36Sopenharmony_ci (bonding_info->master.bond_mode != BOND_MODE_XOR) && 294862306a36Sopenharmony_ci (bonding_info->master.bond_mode != BOND_MODE_8023AD)) 294962306a36Sopenharmony_ci do_bond = false; 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci /* require exactly 2 slaves */ 295262306a36Sopenharmony_ci if (bonding_info->master.num_slaves != 2) 295362306a36Sopenharmony_ci do_bond = false; 295462306a36Sopenharmony_ci 295562306a36Sopenharmony_ci /* calc v2p */ 295662306a36Sopenharmony_ci if (do_bond) { 295762306a36Sopenharmony_ci if (bonding_info->master.bond_mode == 295862306a36Sopenharmony_ci BOND_MODE_ACTIVEBACKUP) { 295962306a36Sopenharmony_ci /* in active-backup mode virtual ports are 296062306a36Sopenharmony_ci * mapped to the physical port of the active 296162306a36Sopenharmony_ci * slave */ 296262306a36Sopenharmony_ci if (bonding_info->slave.state == 296362306a36Sopenharmony_ci BOND_STATE_BACKUP) { 296462306a36Sopenharmony_ci if (port == 1) { 296562306a36Sopenharmony_ci v2p_port1 = 2; 296662306a36Sopenharmony_ci v2p_port2 = 2; 296762306a36Sopenharmony_ci } else { 296862306a36Sopenharmony_ci v2p_port1 = 1; 296962306a36Sopenharmony_ci v2p_port2 = 1; 297062306a36Sopenharmony_ci } 297162306a36Sopenharmony_ci } else { /* BOND_STATE_ACTIVE */ 297262306a36Sopenharmony_ci if (port == 1) { 297362306a36Sopenharmony_ci v2p_port1 = 1; 297462306a36Sopenharmony_ci v2p_port2 = 1; 297562306a36Sopenharmony_ci } else { 297662306a36Sopenharmony_ci v2p_port1 = 2; 297762306a36Sopenharmony_ci v2p_port2 = 2; 297862306a36Sopenharmony_ci } 297962306a36Sopenharmony_ci } 298062306a36Sopenharmony_ci } else { /* Active-Active */ 298162306a36Sopenharmony_ci /* in active-active mode a virtual port is 298262306a36Sopenharmony_ci * mapped to the native physical port if and only 298362306a36Sopenharmony_ci * if the physical port is up */ 298462306a36Sopenharmony_ci __s8 link = bonding_info->slave.link; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci if (port == 1) 298762306a36Sopenharmony_ci v2p_port2 = 2; 298862306a36Sopenharmony_ci else 298962306a36Sopenharmony_ci v2p_port1 = 1; 299062306a36Sopenharmony_ci if ((link == BOND_LINK_UP) || 299162306a36Sopenharmony_ci (link == BOND_LINK_FAIL)) { 299262306a36Sopenharmony_ci if (port == 1) 299362306a36Sopenharmony_ci v2p_port1 = 1; 299462306a36Sopenharmony_ci else 299562306a36Sopenharmony_ci v2p_port2 = 2; 299662306a36Sopenharmony_ci } else { /* BOND_LINK_DOWN || BOND_LINK_BACK */ 299762306a36Sopenharmony_ci if (port == 1) 299862306a36Sopenharmony_ci v2p_port1 = 2; 299962306a36Sopenharmony_ci else 300062306a36Sopenharmony_ci v2p_port2 = 1; 300162306a36Sopenharmony_ci } 300262306a36Sopenharmony_ci } 300362306a36Sopenharmony_ci } 300462306a36Sopenharmony_ci } 300562306a36Sopenharmony_ci 300662306a36Sopenharmony_ci mlx4_queue_bond_work(dev, do_bond, v2p_port1, v2p_port2); 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci return NOTIFY_DONE; 300962306a36Sopenharmony_ci} 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_civoid mlx4_en_update_pfc_stats_bitmap(struct mlx4_dev *dev, 301262306a36Sopenharmony_ci struct mlx4_en_stats_bitmap *stats_bitmap, 301362306a36Sopenharmony_ci u8 rx_ppp, u8 rx_pause, 301462306a36Sopenharmony_ci u8 tx_ppp, u8 tx_pause) 301562306a36Sopenharmony_ci{ 301662306a36Sopenharmony_ci int last_i = NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PF_STATS; 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci if (!mlx4_is_slave(dev) && 301962306a36Sopenharmony_ci (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN)) { 302062306a36Sopenharmony_ci mutex_lock(&stats_bitmap->mutex); 302162306a36Sopenharmony_ci bitmap_clear(stats_bitmap->bitmap, last_i, NUM_FLOW_STATS); 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci if (rx_ppp) 302462306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 302562306a36Sopenharmony_ci NUM_FLOW_PRIORITY_STATS_RX); 302662306a36Sopenharmony_ci last_i += NUM_FLOW_PRIORITY_STATS_RX; 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci if (rx_pause && !(rx_ppp)) 302962306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 303062306a36Sopenharmony_ci NUM_FLOW_STATS_RX); 303162306a36Sopenharmony_ci last_i += NUM_FLOW_STATS_RX; 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_ci if (tx_ppp) 303462306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 303562306a36Sopenharmony_ci NUM_FLOW_PRIORITY_STATS_TX); 303662306a36Sopenharmony_ci last_i += NUM_FLOW_PRIORITY_STATS_TX; 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci if (tx_pause && !(tx_ppp)) 303962306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 304062306a36Sopenharmony_ci NUM_FLOW_STATS_TX); 304162306a36Sopenharmony_ci last_i += NUM_FLOW_STATS_TX; 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci mutex_unlock(&stats_bitmap->mutex); 304462306a36Sopenharmony_ci } 304562306a36Sopenharmony_ci} 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_civoid mlx4_en_set_stats_bitmap(struct mlx4_dev *dev, 304862306a36Sopenharmony_ci struct mlx4_en_stats_bitmap *stats_bitmap, 304962306a36Sopenharmony_ci u8 rx_ppp, u8 rx_pause, 305062306a36Sopenharmony_ci u8 tx_ppp, u8 tx_pause) 305162306a36Sopenharmony_ci{ 305262306a36Sopenharmony_ci int last_i = 0; 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci mutex_init(&stats_bitmap->mutex); 305562306a36Sopenharmony_ci bitmap_zero(stats_bitmap->bitmap, NUM_ALL_STATS); 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci if (mlx4_is_slave(dev)) { 305862306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 305962306a36Sopenharmony_ci MLX4_FIND_NETDEV_STAT(rx_packets), 1); 306062306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 306162306a36Sopenharmony_ci MLX4_FIND_NETDEV_STAT(tx_packets), 1); 306262306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 306362306a36Sopenharmony_ci MLX4_FIND_NETDEV_STAT(rx_bytes), 1); 306462306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 306562306a36Sopenharmony_ci MLX4_FIND_NETDEV_STAT(tx_bytes), 1); 306662306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 306762306a36Sopenharmony_ci MLX4_FIND_NETDEV_STAT(rx_dropped), 1); 306862306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 306962306a36Sopenharmony_ci MLX4_FIND_NETDEV_STAT(tx_dropped), 1); 307062306a36Sopenharmony_ci } else { 307162306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_MAIN_STATS); 307262306a36Sopenharmony_ci } 307362306a36Sopenharmony_ci last_i += NUM_MAIN_STATS; 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_PORT_STATS); 307662306a36Sopenharmony_ci last_i += NUM_PORT_STATS; 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci if (mlx4_is_master(dev)) 307962306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 308062306a36Sopenharmony_ci NUM_PF_STATS); 308162306a36Sopenharmony_ci last_i += NUM_PF_STATS; 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_ci mlx4_en_update_pfc_stats_bitmap(dev, stats_bitmap, 308462306a36Sopenharmony_ci rx_ppp, rx_pause, 308562306a36Sopenharmony_ci tx_ppp, tx_pause); 308662306a36Sopenharmony_ci last_i += NUM_FLOW_STATS; 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_ci if (!mlx4_is_slave(dev)) 308962306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_PKT_STATS); 309062306a36Sopenharmony_ci last_i += NUM_PKT_STATS; 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_XDP_STATS); 309362306a36Sopenharmony_ci last_i += NUM_XDP_STATS; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci if (!mlx4_is_slave(dev)) 309662306a36Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_PHY_STATS); 309762306a36Sopenharmony_ci last_i += NUM_PHY_STATS; 309862306a36Sopenharmony_ci} 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_ciint mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, 310162306a36Sopenharmony_ci struct mlx4_en_port_profile *prof) 310262306a36Sopenharmony_ci{ 310362306a36Sopenharmony_ci struct net_device *dev; 310462306a36Sopenharmony_ci struct mlx4_en_priv *priv; 310562306a36Sopenharmony_ci int i, t; 310662306a36Sopenharmony_ci int err; 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv), 310962306a36Sopenharmony_ci MAX_TX_RINGS, MAX_RX_RINGS); 311062306a36Sopenharmony_ci if (dev == NULL) 311162306a36Sopenharmony_ci return -ENOMEM; 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci netif_set_real_num_tx_queues(dev, prof->tx_ring_num[TX]); 311462306a36Sopenharmony_ci netif_set_real_num_rx_queues(dev, prof->rx_ring_num); 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &mdev->dev->persist->pdev->dev); 311762306a36Sopenharmony_ci dev->dev_port = port - 1; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci /* 312062306a36Sopenharmony_ci * Initialize driver private data 312162306a36Sopenharmony_ci */ 312262306a36Sopenharmony_ci 312362306a36Sopenharmony_ci priv = netdev_priv(dev); 312462306a36Sopenharmony_ci memset(priv, 0, sizeof(struct mlx4_en_priv)); 312562306a36Sopenharmony_ci priv->counter_index = MLX4_SINK_COUNTER_INDEX(mdev->dev); 312662306a36Sopenharmony_ci spin_lock_init(&priv->stats_lock); 312762306a36Sopenharmony_ci INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); 312862306a36Sopenharmony_ci INIT_WORK(&priv->restart_task, mlx4_en_restart); 312962306a36Sopenharmony_ci INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate_work); 313062306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); 313162306a36Sopenharmony_ci INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task); 313262306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 313362306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->filters); 313462306a36Sopenharmony_ci spin_lock_init(&priv->filters_lock); 313562306a36Sopenharmony_ci#endif 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci priv->dev = dev; 313862306a36Sopenharmony_ci priv->mdev = mdev; 313962306a36Sopenharmony_ci priv->ddev = &mdev->pdev->dev; 314062306a36Sopenharmony_ci priv->prof = prof; 314162306a36Sopenharmony_ci priv->port = port; 314262306a36Sopenharmony_ci priv->port_up = false; 314362306a36Sopenharmony_ci priv->flags = prof->flags; 314462306a36Sopenharmony_ci priv->pflags = MLX4_EN_PRIV_FLAGS_BLUEFLAME; 314562306a36Sopenharmony_ci priv->ctrl_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE | 314662306a36Sopenharmony_ci MLX4_WQE_CTRL_SOLICITED); 314762306a36Sopenharmony_ci priv->num_tx_rings_p_up = mdev->profile.max_num_tx_rings_p_up; 314862306a36Sopenharmony_ci priv->tx_work_limit = MLX4_EN_DEFAULT_TX_WORK; 314962306a36Sopenharmony_ci netdev_rss_key_fill(priv->rss_key, sizeof(priv->rss_key)); 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 315262306a36Sopenharmony_ci priv->tx_ring_num[t] = prof->tx_ring_num[t]; 315362306a36Sopenharmony_ci if (!priv->tx_ring_num[t]) 315462306a36Sopenharmony_ci continue; 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci priv->tx_ring[t] = kcalloc(MAX_TX_RINGS, 315762306a36Sopenharmony_ci sizeof(struct mlx4_en_tx_ring *), 315862306a36Sopenharmony_ci GFP_KERNEL); 315962306a36Sopenharmony_ci if (!priv->tx_ring[t]) { 316062306a36Sopenharmony_ci err = -ENOMEM; 316162306a36Sopenharmony_ci goto out; 316262306a36Sopenharmony_ci } 316362306a36Sopenharmony_ci priv->tx_cq[t] = kcalloc(MAX_TX_RINGS, 316462306a36Sopenharmony_ci sizeof(struct mlx4_en_cq *), 316562306a36Sopenharmony_ci GFP_KERNEL); 316662306a36Sopenharmony_ci if (!priv->tx_cq[t]) { 316762306a36Sopenharmony_ci err = -ENOMEM; 316862306a36Sopenharmony_ci goto out; 316962306a36Sopenharmony_ci } 317062306a36Sopenharmony_ci } 317162306a36Sopenharmony_ci priv->rx_ring_num = prof->rx_ring_num; 317262306a36Sopenharmony_ci priv->cqe_factor = (mdev->dev->caps.cqe_size == 64) ? 1 : 0; 317362306a36Sopenharmony_ci priv->cqe_size = mdev->dev->caps.cqe_size; 317462306a36Sopenharmony_ci priv->mac_index = -1; 317562306a36Sopenharmony_ci priv->msg_enable = MLX4_EN_MSG_LEVEL; 317662306a36Sopenharmony_ci#ifdef CONFIG_MLX4_EN_DCB 317762306a36Sopenharmony_ci if (!mlx4_is_slave(priv->mdev->dev)) { 317862306a36Sopenharmony_ci u8 prio; 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; ++prio) { 318162306a36Sopenharmony_ci priv->ets.prio_tc[prio] = prio; 318262306a36Sopenharmony_ci priv->ets.tc_tsa[prio] = IEEE_8021QAZ_TSA_VENDOR; 318362306a36Sopenharmony_ci } 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci priv->dcbx_cap = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_HOST | 318662306a36Sopenharmony_ci DCB_CAP_DCBX_VER_IEEE; 318762306a36Sopenharmony_ci priv->flags |= MLX4_EN_DCB_ENABLED; 318862306a36Sopenharmony_ci priv->cee_config.pfc_state = false; 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci for (i = 0; i < MLX4_EN_NUM_UP_HIGH; i++) 319162306a36Sopenharmony_ci priv->cee_config.dcb_pfc[i] = pfc_disabled; 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) { 319462306a36Sopenharmony_ci dev->dcbnl_ops = &mlx4_en_dcbnl_ops; 319562306a36Sopenharmony_ci } else { 319662306a36Sopenharmony_ci en_info(priv, "enabling only PFC DCB ops\n"); 319762306a36Sopenharmony_ci dev->dcbnl_ops = &mlx4_en_dcbnl_pfc_ops; 319862306a36Sopenharmony_ci } 319962306a36Sopenharmony_ci } 320062306a36Sopenharmony_ci#endif 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ci for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) 320362306a36Sopenharmony_ci INIT_HLIST_HEAD(&priv->mac_hash[i]); 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci /* Query for default mac and max mtu */ 320662306a36Sopenharmony_ci priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci if (mdev->dev->caps.rx_checksum_flags_port[priv->port] & 320962306a36Sopenharmony_ci MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP) 321062306a36Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP; 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci /* Set default MAC */ 321362306a36Sopenharmony_ci dev->addr_len = ETH_ALEN; 321462306a36Sopenharmony_ci mlx4_en_u64_to_mac(dev, mdev->dev->caps.def_mac[priv->port]); 321562306a36Sopenharmony_ci if (!is_valid_ether_addr(dev->dev_addr)) { 321662306a36Sopenharmony_ci en_err(priv, "Port: %d, invalid mac burned: %pM, quitting\n", 321762306a36Sopenharmony_ci priv->port, dev->dev_addr); 321862306a36Sopenharmony_ci err = -EINVAL; 321962306a36Sopenharmony_ci goto out; 322062306a36Sopenharmony_ci } else if (mlx4_is_slave(priv->mdev->dev) && 322162306a36Sopenharmony_ci (priv->mdev->dev->port_random_macs & 1 << priv->port)) { 322262306a36Sopenharmony_ci /* Random MAC was assigned in mlx4_slave_cap 322362306a36Sopenharmony_ci * in mlx4_core module 322462306a36Sopenharmony_ci */ 322562306a36Sopenharmony_ci dev->addr_assign_type |= NET_ADDR_RANDOM; 322662306a36Sopenharmony_ci en_warn(priv, "Assigned random MAC address %pM\n", dev->dev_addr); 322762306a36Sopenharmony_ci } 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci memcpy(priv->current_mac, dev->dev_addr, sizeof(priv->current_mac)); 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + 323262306a36Sopenharmony_ci DS_SIZE * MLX4_EN_MAX_RX_FRAGS); 323362306a36Sopenharmony_ci err = mlx4_en_alloc_resources(priv); 323462306a36Sopenharmony_ci if (err) 323562306a36Sopenharmony_ci goto out; 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci /* Initialize time stamping config */ 323862306a36Sopenharmony_ci priv->hwtstamp_config.flags = 0; 323962306a36Sopenharmony_ci priv->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF; 324062306a36Sopenharmony_ci priv->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; 324162306a36Sopenharmony_ci 324262306a36Sopenharmony_ci /* Allocate page for receive rings */ 324362306a36Sopenharmony_ci err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, 324462306a36Sopenharmony_ci MLX4_EN_PAGE_SIZE); 324562306a36Sopenharmony_ci if (err) { 324662306a36Sopenharmony_ci en_err(priv, "Failed to allocate page for rx qps\n"); 324762306a36Sopenharmony_ci goto out; 324862306a36Sopenharmony_ci } 324962306a36Sopenharmony_ci priv->allocated = 1; 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci /* 325262306a36Sopenharmony_ci * Initialize netdev entry points 325362306a36Sopenharmony_ci */ 325462306a36Sopenharmony_ci if (mlx4_is_master(priv->mdev->dev)) 325562306a36Sopenharmony_ci dev->netdev_ops = &mlx4_netdev_ops_master; 325662306a36Sopenharmony_ci else 325762306a36Sopenharmony_ci dev->netdev_ops = &mlx4_netdev_ops; 325862306a36Sopenharmony_ci dev->xdp_metadata_ops = &mlx4_xdp_metadata_ops; 325962306a36Sopenharmony_ci dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT; 326062306a36Sopenharmony_ci netif_set_real_num_tx_queues(dev, priv->tx_ring_num[TX]); 326162306a36Sopenharmony_ci netif_set_real_num_rx_queues(dev, priv->rx_ring_num); 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci dev->ethtool_ops = &mlx4_en_ethtool_ops; 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci /* 326662306a36Sopenharmony_ci * Set driver features 326762306a36Sopenharmony_ci */ 326862306a36Sopenharmony_ci dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; 326962306a36Sopenharmony_ci if (mdev->LSO_support) 327062306a36Sopenharmony_ci dev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci if (mdev->dev->caps.tunnel_offload_mode == 327362306a36Sopenharmony_ci MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) { 327462306a36Sopenharmony_ci dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL | 327562306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 327662306a36Sopenharmony_ci NETIF_F_GSO_PARTIAL; 327762306a36Sopenharmony_ci dev->features |= NETIF_F_GSO_UDP_TUNNEL | 327862306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 327962306a36Sopenharmony_ci NETIF_F_GSO_PARTIAL; 328062306a36Sopenharmony_ci dev->gso_partial_features = NETIF_F_GSO_UDP_TUNNEL_CSUM; 328162306a36Sopenharmony_ci dev->hw_enc_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 328262306a36Sopenharmony_ci NETIF_F_RXCSUM | 328362306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6 | 328462306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL | 328562306a36Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 328662306a36Sopenharmony_ci NETIF_F_GSO_PARTIAL; 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci dev->udp_tunnel_nic_info = &mlx4_udp_tunnels; 328962306a36Sopenharmony_ci } 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci dev->vlan_features = dev->hw_features; 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_ci dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_RXHASH; 329462306a36Sopenharmony_ci dev->features = dev->hw_features | NETIF_F_HIGHDMA | 329562306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | 329662306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER; 329762306a36Sopenharmony_ci dev->hw_features |= NETIF_F_LOOPBACK | 329862306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) { 330162306a36Sopenharmony_ci dev->features |= NETIF_F_HW_VLAN_STAG_RX | 330262306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_FILTER; 330362306a36Sopenharmony_ci dev->hw_features |= NETIF_F_HW_VLAN_STAG_RX; 330462306a36Sopenharmony_ci } 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_ci if (mlx4_is_slave(mdev->dev)) { 330762306a36Sopenharmony_ci bool vlan_offload_disabled; 330862306a36Sopenharmony_ci int phv; 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ci err = get_phv_bit(mdev->dev, port, &phv); 331162306a36Sopenharmony_ci if (!err && phv) { 331262306a36Sopenharmony_ci dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX; 331362306a36Sopenharmony_ci priv->pflags |= MLX4_EN_PRIV_FLAGS_PHV; 331462306a36Sopenharmony_ci } 331562306a36Sopenharmony_ci err = mlx4_get_is_vlan_offload_disabled(mdev->dev, port, 331662306a36Sopenharmony_ci &vlan_offload_disabled); 331762306a36Sopenharmony_ci if (!err && vlan_offload_disabled) { 331862306a36Sopenharmony_ci dev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_TX | 331962306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | 332062306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX | 332162306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_RX); 332262306a36Sopenharmony_ci dev->features &= ~(NETIF_F_HW_VLAN_CTAG_TX | 332362306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | 332462306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX | 332562306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_RX); 332662306a36Sopenharmony_ci } 332762306a36Sopenharmony_ci } else { 332862306a36Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN && 332962306a36Sopenharmony_ci !(mdev->dev->caps.flags2 & 333062306a36Sopenharmony_ci MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) 333162306a36Sopenharmony_ci dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX; 333262306a36Sopenharmony_ci } 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) 333562306a36Sopenharmony_ci dev->hw_features |= NETIF_F_RXFCS; 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_IGNORE_FCS) 333862306a36Sopenharmony_ci dev->hw_features |= NETIF_F_RXALL; 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_ci if (mdev->dev->caps.steering_mode == 334162306a36Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED && 334262306a36Sopenharmony_ci mdev->dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC) 334362306a36Sopenharmony_ci dev->hw_features |= NETIF_F_NTUPLE; 334462306a36Sopenharmony_ci 334562306a36Sopenharmony_ci if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 334662306a36Sopenharmony_ci dev->priv_flags |= IFF_UNICAST_FLT; 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci /* Setting a default hash function value */ 334962306a36Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP) { 335062306a36Sopenharmony_ci priv->rss_hash_fn = ETH_RSS_HASH_TOP; 335162306a36Sopenharmony_ci } else if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_XOR) { 335262306a36Sopenharmony_ci priv->rss_hash_fn = ETH_RSS_HASH_XOR; 335362306a36Sopenharmony_ci } else { 335462306a36Sopenharmony_ci en_warn(priv, 335562306a36Sopenharmony_ci "No RSS hash capabilities exposed, using Toeplitz\n"); 335662306a36Sopenharmony_ci priv->rss_hash_fn = ETH_RSS_HASH_TOP; 335762306a36Sopenharmony_ci } 335862306a36Sopenharmony_ci 335962306a36Sopenharmony_ci dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT; 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ci /* MTU range: 68 - hw-specific max */ 336262306a36Sopenharmony_ci dev->min_mtu = ETH_MIN_MTU; 336362306a36Sopenharmony_ci dev->max_mtu = priv->max_mtu; 336462306a36Sopenharmony_ci 336562306a36Sopenharmony_ci /* supports LSOv2 packets. */ 336662306a36Sopenharmony_ci netif_set_tso_max_size(dev, GSO_MAX_SIZE); 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_ci mdev->pndev[port] = dev; 336962306a36Sopenharmony_ci mdev->upper[port] = NULL; 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ci netif_carrier_off(dev); 337262306a36Sopenharmony_ci mlx4_en_set_default_moderation(priv); 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_ci en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num[TX]); 337562306a36Sopenharmony_ci en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci mlx4_en_update_loopback_state(priv->dev, priv->dev->features); 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci /* Configure port */ 338062306a36Sopenharmony_ci mlx4_en_calc_rx_buf(dev); 338162306a36Sopenharmony_ci err = mlx4_SET_PORT_general(mdev->dev, priv->port, 338262306a36Sopenharmony_ci priv->rx_skb_size + ETH_FCS_LEN, 338362306a36Sopenharmony_ci prof->tx_pause, prof->tx_ppp, 338462306a36Sopenharmony_ci prof->rx_pause, prof->rx_ppp); 338562306a36Sopenharmony_ci if (err) { 338662306a36Sopenharmony_ci en_err(priv, "Failed setting port general configurations for port %d, with error %d\n", 338762306a36Sopenharmony_ci priv->port, err); 338862306a36Sopenharmony_ci goto out; 338962306a36Sopenharmony_ci } 339062306a36Sopenharmony_ci 339162306a36Sopenharmony_ci if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) { 339262306a36Sopenharmony_ci err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC, 1); 339362306a36Sopenharmony_ci if (err) { 339462306a36Sopenharmony_ci en_err(priv, "Failed setting port L2 tunnel configuration, err %d\n", 339562306a36Sopenharmony_ci err); 339662306a36Sopenharmony_ci goto out; 339762306a36Sopenharmony_ci } 339862306a36Sopenharmony_ci } 339962306a36Sopenharmony_ci 340062306a36Sopenharmony_ci /* Init port */ 340162306a36Sopenharmony_ci en_warn(priv, "Initializing port\n"); 340262306a36Sopenharmony_ci err = mlx4_INIT_PORT(mdev->dev, priv->port); 340362306a36Sopenharmony_ci if (err) { 340462306a36Sopenharmony_ci en_err(priv, "Failed Initializing port\n"); 340562306a36Sopenharmony_ci goto out; 340662306a36Sopenharmony_ci } 340762306a36Sopenharmony_ci queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci /* Initialize time stamp mechanism */ 341062306a36Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) 341162306a36Sopenharmony_ci mlx4_en_init_timestamp(mdev); 341262306a36Sopenharmony_ci 341362306a36Sopenharmony_ci queue_delayed_work(mdev->workqueue, &priv->service_task, 341462306a36Sopenharmony_ci SERVICE_TASK_DELAY); 341562306a36Sopenharmony_ci 341662306a36Sopenharmony_ci mlx4_en_set_stats_bitmap(mdev->dev, &priv->stats_bitmap, 341762306a36Sopenharmony_ci mdev->profile.prof[priv->port].rx_ppp, 341862306a36Sopenharmony_ci mdev->profile.prof[priv->port].rx_pause, 341962306a36Sopenharmony_ci mdev->profile.prof[priv->port].tx_ppp, 342062306a36Sopenharmony_ci mdev->profile.prof[priv->port].tx_pause); 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ci SET_NETDEV_DEVLINK_PORT(dev, 342362306a36Sopenharmony_ci mlx4_get_devlink_port(mdev->dev, priv->port)); 342462306a36Sopenharmony_ci err = register_netdev(dev); 342562306a36Sopenharmony_ci if (err) { 342662306a36Sopenharmony_ci en_err(priv, "Netdev registration failed for port %d\n", port); 342762306a36Sopenharmony_ci goto out; 342862306a36Sopenharmony_ci } 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci priv->registered = 1; 343162306a36Sopenharmony_ci 343262306a36Sopenharmony_ci return 0; 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ciout: 343562306a36Sopenharmony_ci mlx4_en_destroy_netdev(dev); 343662306a36Sopenharmony_ci return err; 343762306a36Sopenharmony_ci} 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_ciint mlx4_en_reset_config(struct net_device *dev, 344062306a36Sopenharmony_ci struct hwtstamp_config ts_config, 344162306a36Sopenharmony_ci netdev_features_t features) 344262306a36Sopenharmony_ci{ 344362306a36Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 344462306a36Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 344562306a36Sopenharmony_ci struct mlx4_en_port_profile new_prof; 344662306a36Sopenharmony_ci struct mlx4_en_priv *tmp; 344762306a36Sopenharmony_ci int port_up = 0; 344862306a36Sopenharmony_ci int err = 0; 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci if (priv->hwtstamp_config.tx_type == ts_config.tx_type && 345162306a36Sopenharmony_ci priv->hwtstamp_config.rx_filter == ts_config.rx_filter && 345262306a36Sopenharmony_ci !DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX) && 345362306a36Sopenharmony_ci !DEV_FEATURE_CHANGED(dev, features, NETIF_F_RXFCS)) 345462306a36Sopenharmony_ci return 0; /* Nothing to change */ 345562306a36Sopenharmony_ci 345662306a36Sopenharmony_ci if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX) && 345762306a36Sopenharmony_ci (features & NETIF_F_HW_VLAN_CTAG_RX) && 345862306a36Sopenharmony_ci (priv->hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE)) { 345962306a36Sopenharmony_ci en_warn(priv, "Can't turn ON rx vlan offload while time-stamping rx filter is ON\n"); 346062306a36Sopenharmony_ci return -EINVAL; 346162306a36Sopenharmony_ci } 346262306a36Sopenharmony_ci 346362306a36Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 346462306a36Sopenharmony_ci if (!tmp) 346562306a36Sopenharmony_ci return -ENOMEM; 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci mutex_lock(&mdev->state_lock); 346862306a36Sopenharmony_ci 346962306a36Sopenharmony_ci memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); 347062306a36Sopenharmony_ci memcpy(&new_prof.hwtstamp_config, &ts_config, sizeof(ts_config)); 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); 347362306a36Sopenharmony_ci if (err) 347462306a36Sopenharmony_ci goto out; 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci if (priv->port_up) { 347762306a36Sopenharmony_ci port_up = 1; 347862306a36Sopenharmony_ci mlx4_en_stop_port(dev, 1); 347962306a36Sopenharmony_ci } 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci mlx4_en_safe_replace_resources(priv, tmp); 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX)) { 348462306a36Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX) 348562306a36Sopenharmony_ci dev->features |= NETIF_F_HW_VLAN_CTAG_RX; 348662306a36Sopenharmony_ci else 348762306a36Sopenharmony_ci dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; 348862306a36Sopenharmony_ci } else if (ts_config.rx_filter == HWTSTAMP_FILTER_NONE) { 348962306a36Sopenharmony_ci /* RX time-stamping is OFF, update the RX vlan offload 349062306a36Sopenharmony_ci * to the latest wanted state 349162306a36Sopenharmony_ci */ 349262306a36Sopenharmony_ci if (dev->wanted_features & NETIF_F_HW_VLAN_CTAG_RX) 349362306a36Sopenharmony_ci dev->features |= NETIF_F_HW_VLAN_CTAG_RX; 349462306a36Sopenharmony_ci else 349562306a36Sopenharmony_ci dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; 349662306a36Sopenharmony_ci } 349762306a36Sopenharmony_ci 349862306a36Sopenharmony_ci if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_RXFCS)) { 349962306a36Sopenharmony_ci if (features & NETIF_F_RXFCS) 350062306a36Sopenharmony_ci dev->features |= NETIF_F_RXFCS; 350162306a36Sopenharmony_ci else 350262306a36Sopenharmony_ci dev->features &= ~NETIF_F_RXFCS; 350362306a36Sopenharmony_ci } 350462306a36Sopenharmony_ci 350562306a36Sopenharmony_ci /* RX vlan offload and RX time-stamping can't co-exist ! 350662306a36Sopenharmony_ci * Regardless of the caller's choice, 350762306a36Sopenharmony_ci * Turn Off RX vlan offload in case of time-stamping is ON 350862306a36Sopenharmony_ci */ 350962306a36Sopenharmony_ci if (ts_config.rx_filter != HWTSTAMP_FILTER_NONE) { 351062306a36Sopenharmony_ci if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) 351162306a36Sopenharmony_ci en_warn(priv, "Turning off RX vlan offload since RX time-stamping is ON\n"); 351262306a36Sopenharmony_ci dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; 351362306a36Sopenharmony_ci } 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci if (port_up) { 351662306a36Sopenharmony_ci err = mlx4_en_start_port(dev); 351762306a36Sopenharmony_ci if (err) 351862306a36Sopenharmony_ci en_err(priv, "Failed starting port\n"); 351962306a36Sopenharmony_ci } 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci if (!err) 352262306a36Sopenharmony_ci err = mlx4_en_moderation_update(priv); 352362306a36Sopenharmony_ciout: 352462306a36Sopenharmony_ci mutex_unlock(&mdev->state_lock); 352562306a36Sopenharmony_ci kfree(tmp); 352662306a36Sopenharmony_ci if (!err) 352762306a36Sopenharmony_ci netdev_features_change(dev); 352862306a36Sopenharmony_ci return err; 352962306a36Sopenharmony_ci} 3530