18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/bpf.h> 358c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 368c2ecf20Sopenharmony_ci#include <linux/tcp.h> 378c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 388c2ecf20Sopenharmony_ci#include <linux/delay.h> 398c2ecf20Sopenharmony_ci#include <linux/slab.h> 408c2ecf20Sopenharmony_ci#include <linux/hash.h> 418c2ecf20Sopenharmony_ci#include <net/ip.h> 428c2ecf20Sopenharmony_ci#include <net/vxlan.h> 438c2ecf20Sopenharmony_ci#include <net/devlink.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include <linux/mlx4/driver.h> 468c2ecf20Sopenharmony_ci#include <linux/mlx4/device.h> 478c2ecf20Sopenharmony_ci#include <linux/mlx4/cmd.h> 488c2ecf20Sopenharmony_ci#include <linux/mlx4/cq.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#include "mlx4_en.h" 518c2ecf20Sopenharmony_ci#include "en_port.h" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define MLX4_EN_MAX_XDP_MTU ((int)(PAGE_SIZE - ETH_HLEN - (2 * VLAN_HLEN) - \ 548c2ecf20Sopenharmony_ci XDP_PACKET_HEADROOM - \ 558c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciint mlx4_en_setup_tc(struct net_device *dev, u8 up) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 608c2ecf20Sopenharmony_ci int i; 618c2ecf20Sopenharmony_ci unsigned int offset = 0; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (up && up != MLX4_EN_NUM_UP_HIGH) 648c2ecf20Sopenharmony_ci return -EINVAL; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci netdev_set_num_tc(dev, up); 678c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(dev, priv->tx_ring_num[TX]); 688c2ecf20Sopenharmony_ci /* Partition Tx queues evenly amongst UP's */ 698c2ecf20Sopenharmony_ci for (i = 0; i < up; i++) { 708c2ecf20Sopenharmony_ci netdev_set_tc_queue(dev, i, priv->num_tx_rings_p_up, offset); 718c2ecf20Sopenharmony_ci offset += priv->num_tx_rings_p_up; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#ifdef CONFIG_MLX4_EN_DCB 758c2ecf20Sopenharmony_ci if (!mlx4_is_slave(priv->mdev->dev)) { 768c2ecf20Sopenharmony_ci if (up) { 778c2ecf20Sopenharmony_ci if (priv->dcbx_cap) 788c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_DCB_ENABLED; 798c2ecf20Sopenharmony_ci } else { 808c2ecf20Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_DCB_ENABLED; 818c2ecf20Sopenharmony_ci priv->cee_config.pfc_state = false; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci#endif /* CONFIG_MLX4_EN_DCB */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciint mlx4_en_alloc_tx_queue_per_tc(struct net_device *dev, u8 tc) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 928c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 938c2ecf20Sopenharmony_ci struct mlx4_en_port_profile new_prof; 948c2ecf20Sopenharmony_ci struct mlx4_en_priv *tmp; 958c2ecf20Sopenharmony_ci int total_count; 968c2ecf20Sopenharmony_ci int port_up = 0; 978c2ecf20Sopenharmony_ci int err = 0; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 1008c2ecf20Sopenharmony_ci if (!tmp) 1018c2ecf20Sopenharmony_ci return -ENOMEM; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 1048c2ecf20Sopenharmony_ci memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); 1058c2ecf20Sopenharmony_ci new_prof.num_up = (tc == 0) ? MLX4_EN_NUM_UP_LOW : 1068c2ecf20Sopenharmony_ci MLX4_EN_NUM_UP_HIGH; 1078c2ecf20Sopenharmony_ci new_prof.tx_ring_num[TX] = new_prof.num_tx_rings_p_up * 1088c2ecf20Sopenharmony_ci new_prof.num_up; 1098c2ecf20Sopenharmony_ci total_count = new_prof.tx_ring_num[TX] + new_prof.tx_ring_num[TX_XDP]; 1108c2ecf20Sopenharmony_ci if (total_count > MAX_TX_RINGS) { 1118c2ecf20Sopenharmony_ci err = -EINVAL; 1128c2ecf20Sopenharmony_ci en_err(priv, 1138c2ecf20Sopenharmony_ci "Total number of TX and XDP rings (%d) exceeds the maximum supported (%d)\n", 1148c2ecf20Sopenharmony_ci total_count, MAX_TX_RINGS); 1158c2ecf20Sopenharmony_ci goto out; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); 1188c2ecf20Sopenharmony_ci if (err) 1198c2ecf20Sopenharmony_ci goto out; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (priv->port_up) { 1228c2ecf20Sopenharmony_ci port_up = 1; 1238c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 1); 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci mlx4_en_safe_replace_resources(priv, tmp); 1278c2ecf20Sopenharmony_ci if (port_up) { 1288c2ecf20Sopenharmony_ci err = mlx4_en_start_port(dev); 1298c2ecf20Sopenharmony_ci if (err) { 1308c2ecf20Sopenharmony_ci en_err(priv, "Failed starting port for setup TC\n"); 1318c2ecf20Sopenharmony_ci goto out; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci err = mlx4_en_setup_tc(dev, tc); 1368c2ecf20Sopenharmony_ciout: 1378c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 1388c2ecf20Sopenharmony_ci kfree(tmp); 1398c2ecf20Sopenharmony_ci return err; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int __mlx4_en_setup_tc(struct net_device *dev, enum tc_setup_type type, 1438c2ecf20Sopenharmony_ci void *type_data) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct tc_mqprio_qopt *mqprio = type_data; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (type != TC_SETUP_QDISC_MQPRIO) 1488c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (mqprio->num_tc && mqprio->num_tc != MLX4_EN_NUM_UP_HIGH) 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return mlx4_en_alloc_tx_queue_per_tc(dev, mqprio->num_tc); 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistruct mlx4_en_filter { 1618c2ecf20Sopenharmony_ci struct list_head next; 1628c2ecf20Sopenharmony_ci struct work_struct work; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci u8 ip_proto; 1658c2ecf20Sopenharmony_ci __be32 src_ip; 1668c2ecf20Sopenharmony_ci __be32 dst_ip; 1678c2ecf20Sopenharmony_ci __be16 src_port; 1688c2ecf20Sopenharmony_ci __be16 dst_port; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci int rxq_index; 1718c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv; 1728c2ecf20Sopenharmony_ci u32 flow_id; /* RFS infrastructure id */ 1738c2ecf20Sopenharmony_ci int id; /* mlx4_en driver id */ 1748c2ecf20Sopenharmony_ci u64 reg_id; /* Flow steering API id */ 1758c2ecf20Sopenharmony_ci u8 activated; /* Used to prevent expiry before filter 1768c2ecf20Sopenharmony_ci * is attached 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci struct hlist_node filter_chain; 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic enum mlx4_net_trans_rule_id mlx4_ip_proto_to_trans_rule_id(u8 ip_proto) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci switch (ip_proto) { 1868c2ecf20Sopenharmony_ci case IPPROTO_UDP: 1878c2ecf20Sopenharmony_ci return MLX4_NET_TRANS_RULE_ID_UDP; 1888c2ecf20Sopenharmony_ci case IPPROTO_TCP: 1898c2ecf20Sopenharmony_ci return MLX4_NET_TRANS_RULE_ID_TCP; 1908c2ecf20Sopenharmony_ci default: 1918c2ecf20Sopenharmony_ci return MLX4_NET_TRANS_RULE_NUM; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* Must not acquire state_lock, as its corresponding work_sync 1968c2ecf20Sopenharmony_ci * is done under it. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_cistatic void mlx4_en_filter_work(struct work_struct *work) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct mlx4_en_filter *filter = container_of(work, 2018c2ecf20Sopenharmony_ci struct mlx4_en_filter, 2028c2ecf20Sopenharmony_ci work); 2038c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = filter->priv; 2048c2ecf20Sopenharmony_ci struct mlx4_spec_list spec_tcp_udp = { 2058c2ecf20Sopenharmony_ci .id = mlx4_ip_proto_to_trans_rule_id(filter->ip_proto), 2068c2ecf20Sopenharmony_ci { 2078c2ecf20Sopenharmony_ci .tcp_udp = { 2088c2ecf20Sopenharmony_ci .dst_port = filter->dst_port, 2098c2ecf20Sopenharmony_ci .dst_port_msk = (__force __be16)-1, 2108c2ecf20Sopenharmony_ci .src_port = filter->src_port, 2118c2ecf20Sopenharmony_ci .src_port_msk = (__force __be16)-1, 2128c2ecf20Sopenharmony_ci }, 2138c2ecf20Sopenharmony_ci }, 2148c2ecf20Sopenharmony_ci }; 2158c2ecf20Sopenharmony_ci struct mlx4_spec_list spec_ip = { 2168c2ecf20Sopenharmony_ci .id = MLX4_NET_TRANS_RULE_ID_IPV4, 2178c2ecf20Sopenharmony_ci { 2188c2ecf20Sopenharmony_ci .ipv4 = { 2198c2ecf20Sopenharmony_ci .dst_ip = filter->dst_ip, 2208c2ecf20Sopenharmony_ci .dst_ip_msk = (__force __be32)-1, 2218c2ecf20Sopenharmony_ci .src_ip = filter->src_ip, 2228c2ecf20Sopenharmony_ci .src_ip_msk = (__force __be32)-1, 2238c2ecf20Sopenharmony_ci }, 2248c2ecf20Sopenharmony_ci }, 2258c2ecf20Sopenharmony_ci }; 2268c2ecf20Sopenharmony_ci struct mlx4_spec_list spec_eth = { 2278c2ecf20Sopenharmony_ci .id = MLX4_NET_TRANS_RULE_ID_ETH, 2288c2ecf20Sopenharmony_ci }; 2298c2ecf20Sopenharmony_ci struct mlx4_net_trans_rule rule = { 2308c2ecf20Sopenharmony_ci .list = LIST_HEAD_INIT(rule.list), 2318c2ecf20Sopenharmony_ci .queue_mode = MLX4_NET_TRANS_Q_LIFO, 2328c2ecf20Sopenharmony_ci .exclusive = 1, 2338c2ecf20Sopenharmony_ci .allow_loopback = 1, 2348c2ecf20Sopenharmony_ci .promisc_mode = MLX4_FS_REGULAR, 2358c2ecf20Sopenharmony_ci .port = priv->port, 2368c2ecf20Sopenharmony_ci .priority = MLX4_DOMAIN_RFS, 2378c2ecf20Sopenharmony_ci }; 2388c2ecf20Sopenharmony_ci int rc; 2398c2ecf20Sopenharmony_ci __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (spec_tcp_udp.id >= MLX4_NET_TRANS_RULE_NUM) { 2428c2ecf20Sopenharmony_ci en_warn(priv, "RFS: ignoring unsupported ip protocol (%d)\n", 2438c2ecf20Sopenharmony_ci filter->ip_proto); 2448c2ecf20Sopenharmony_ci goto ignore; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci list_add_tail(&spec_eth.list, &rule.list); 2478c2ecf20Sopenharmony_ci list_add_tail(&spec_ip.list, &rule.list); 2488c2ecf20Sopenharmony_ci list_add_tail(&spec_tcp_udp.list, &rule.list); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci rule.qpn = priv->rss_map.qps[filter->rxq_index].qpn; 2518c2ecf20Sopenharmony_ci memcpy(spec_eth.eth.dst_mac, priv->dev->dev_addr, ETH_ALEN); 2528c2ecf20Sopenharmony_ci memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci filter->activated = 0; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (filter->reg_id) { 2578c2ecf20Sopenharmony_ci rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); 2588c2ecf20Sopenharmony_ci if (rc && rc != -ENOENT) 2598c2ecf20Sopenharmony_ci en_err(priv, "Error detaching flow. rc = %d\n", rc); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci rc = mlx4_flow_attach(priv->mdev->dev, &rule, &filter->reg_id); 2638c2ecf20Sopenharmony_ci if (rc) 2648c2ecf20Sopenharmony_ci en_err(priv, "Error attaching flow. err = %d\n", rc); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ciignore: 2678c2ecf20Sopenharmony_ci mlx4_en_filter_rfs_expire(priv); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci filter->activated = 1; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic inline struct hlist_head * 2738c2ecf20Sopenharmony_cifilter_hash_bucket(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, 2748c2ecf20Sopenharmony_ci __be16 src_port, __be16 dst_port) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci unsigned long l; 2778c2ecf20Sopenharmony_ci int bucket_idx; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci l = (__force unsigned long)src_port | 2808c2ecf20Sopenharmony_ci ((__force unsigned long)dst_port << 2); 2818c2ecf20Sopenharmony_ci l ^= (__force unsigned long)(src_ip ^ dst_ip); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci bucket_idx = hash_long(l, MLX4_EN_FILTER_HASH_SHIFT); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return &priv->filter_hash[bucket_idx]; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic struct mlx4_en_filter * 2898c2ecf20Sopenharmony_cimlx4_en_filter_alloc(struct mlx4_en_priv *priv, int rxq_index, __be32 src_ip, 2908c2ecf20Sopenharmony_ci __be32 dst_ip, u8 ip_proto, __be16 src_port, 2918c2ecf20Sopenharmony_ci __be16 dst_port, u32 flow_id) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct mlx4_en_filter *filter = NULL; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci filter = kzalloc(sizeof(struct mlx4_en_filter), GFP_ATOMIC); 2968c2ecf20Sopenharmony_ci if (!filter) 2978c2ecf20Sopenharmony_ci return NULL; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci filter->priv = priv; 3008c2ecf20Sopenharmony_ci filter->rxq_index = rxq_index; 3018c2ecf20Sopenharmony_ci INIT_WORK(&filter->work, mlx4_en_filter_work); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci filter->src_ip = src_ip; 3048c2ecf20Sopenharmony_ci filter->dst_ip = dst_ip; 3058c2ecf20Sopenharmony_ci filter->ip_proto = ip_proto; 3068c2ecf20Sopenharmony_ci filter->src_port = src_port; 3078c2ecf20Sopenharmony_ci filter->dst_port = dst_port; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci filter->flow_id = flow_id; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci filter->id = priv->last_filter_id++ % RPS_NO_FILTER; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci list_add_tail(&filter->next, &priv->filters); 3148c2ecf20Sopenharmony_ci hlist_add_head(&filter->filter_chain, 3158c2ecf20Sopenharmony_ci filter_hash_bucket(priv, src_ip, dst_ip, src_port, 3168c2ecf20Sopenharmony_ci dst_port)); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return filter; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic void mlx4_en_filter_free(struct mlx4_en_filter *filter) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = filter->priv; 3248c2ecf20Sopenharmony_ci int rc; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci list_del(&filter->next); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci rc = mlx4_flow_detach(priv->mdev->dev, filter->reg_id); 3298c2ecf20Sopenharmony_ci if (rc && rc != -ENOENT) 3308c2ecf20Sopenharmony_ci en_err(priv, "Error detaching flow. rc = %d\n", rc); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci kfree(filter); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic inline struct mlx4_en_filter * 3368c2ecf20Sopenharmony_cimlx4_en_filter_find(struct mlx4_en_priv *priv, __be32 src_ip, __be32 dst_ip, 3378c2ecf20Sopenharmony_ci u8 ip_proto, __be16 src_port, __be16 dst_port) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct mlx4_en_filter *filter; 3408c2ecf20Sopenharmony_ci struct mlx4_en_filter *ret = NULL; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci hlist_for_each_entry(filter, 3438c2ecf20Sopenharmony_ci filter_hash_bucket(priv, src_ip, dst_ip, 3448c2ecf20Sopenharmony_ci src_port, dst_port), 3458c2ecf20Sopenharmony_ci filter_chain) { 3468c2ecf20Sopenharmony_ci if (filter->src_ip == src_ip && 3478c2ecf20Sopenharmony_ci filter->dst_ip == dst_ip && 3488c2ecf20Sopenharmony_ci filter->ip_proto == ip_proto && 3498c2ecf20Sopenharmony_ci filter->src_port == src_port && 3508c2ecf20Sopenharmony_ci filter->dst_port == dst_port) { 3518c2ecf20Sopenharmony_ci ret = filter; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return ret; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int 3608c2ecf20Sopenharmony_cimlx4_en_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb, 3618c2ecf20Sopenharmony_ci u16 rxq_index, u32 flow_id) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(net_dev); 3648c2ecf20Sopenharmony_ci struct mlx4_en_filter *filter; 3658c2ecf20Sopenharmony_ci const struct iphdr *ip; 3668c2ecf20Sopenharmony_ci const __be16 *ports; 3678c2ecf20Sopenharmony_ci u8 ip_proto; 3688c2ecf20Sopenharmony_ci __be32 src_ip; 3698c2ecf20Sopenharmony_ci __be32 dst_ip; 3708c2ecf20Sopenharmony_ci __be16 src_port; 3718c2ecf20Sopenharmony_ci __be16 dst_port; 3728c2ecf20Sopenharmony_ci int nhoff = skb_network_offset(skb); 3738c2ecf20Sopenharmony_ci int ret = 0; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (skb->encapsulation) 3768c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (skb->protocol != htons(ETH_P_IP)) 3798c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ip = (const struct iphdr *)(skb->data + nhoff); 3828c2ecf20Sopenharmony_ci if (ip_is_fragment(ip)) 3838c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if ((ip->protocol != IPPROTO_TCP) && (ip->protocol != IPPROTO_UDP)) 3868c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 3878c2ecf20Sopenharmony_ci ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci ip_proto = ip->protocol; 3908c2ecf20Sopenharmony_ci src_ip = ip->saddr; 3918c2ecf20Sopenharmony_ci dst_ip = ip->daddr; 3928c2ecf20Sopenharmony_ci src_port = ports[0]; 3938c2ecf20Sopenharmony_ci dst_port = ports[1]; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci spin_lock_bh(&priv->filters_lock); 3968c2ecf20Sopenharmony_ci filter = mlx4_en_filter_find(priv, src_ip, dst_ip, ip_proto, 3978c2ecf20Sopenharmony_ci src_port, dst_port); 3988c2ecf20Sopenharmony_ci if (filter) { 3998c2ecf20Sopenharmony_ci if (filter->rxq_index == rxq_index) 4008c2ecf20Sopenharmony_ci goto out; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci filter->rxq_index = rxq_index; 4038c2ecf20Sopenharmony_ci } else { 4048c2ecf20Sopenharmony_ci filter = mlx4_en_filter_alloc(priv, rxq_index, 4058c2ecf20Sopenharmony_ci src_ip, dst_ip, ip_proto, 4068c2ecf20Sopenharmony_ci src_port, dst_port, flow_id); 4078c2ecf20Sopenharmony_ci if (!filter) { 4088c2ecf20Sopenharmony_ci ret = -ENOMEM; 4098c2ecf20Sopenharmony_ci goto err; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci queue_work(priv->mdev->workqueue, &filter->work); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ciout: 4168c2ecf20Sopenharmony_ci ret = filter->id; 4178c2ecf20Sopenharmony_cierr: 4188c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->filters_lock); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return ret; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_civoid mlx4_en_cleanup_filters(struct mlx4_en_priv *priv) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct mlx4_en_filter *filter, *tmp; 4268c2ecf20Sopenharmony_ci LIST_HEAD(del_list); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci spin_lock_bh(&priv->filters_lock); 4298c2ecf20Sopenharmony_ci list_for_each_entry_safe(filter, tmp, &priv->filters, next) { 4308c2ecf20Sopenharmony_ci list_move(&filter->next, &del_list); 4318c2ecf20Sopenharmony_ci hlist_del(&filter->filter_chain); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->filters_lock); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci list_for_each_entry_safe(filter, tmp, &del_list, next) { 4368c2ecf20Sopenharmony_ci cancel_work_sync(&filter->work); 4378c2ecf20Sopenharmony_ci mlx4_en_filter_free(filter); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct mlx4_en_filter *filter = NULL, *tmp, *last_filter = NULL; 4448c2ecf20Sopenharmony_ci LIST_HEAD(del_list); 4458c2ecf20Sopenharmony_ci int i = 0; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci spin_lock_bh(&priv->filters_lock); 4488c2ecf20Sopenharmony_ci list_for_each_entry_safe(filter, tmp, &priv->filters, next) { 4498c2ecf20Sopenharmony_ci if (i > MLX4_EN_FILTER_EXPIRY_QUOTA) 4508c2ecf20Sopenharmony_ci break; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (filter->activated && 4538c2ecf20Sopenharmony_ci !work_pending(&filter->work) && 4548c2ecf20Sopenharmony_ci rps_may_expire_flow(priv->dev, 4558c2ecf20Sopenharmony_ci filter->rxq_index, filter->flow_id, 4568c2ecf20Sopenharmony_ci filter->id)) { 4578c2ecf20Sopenharmony_ci list_move(&filter->next, &del_list); 4588c2ecf20Sopenharmony_ci hlist_del(&filter->filter_chain); 4598c2ecf20Sopenharmony_ci } else 4608c2ecf20Sopenharmony_ci last_filter = filter; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci i++; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (last_filter && (&last_filter->next != priv->filters.next)) 4668c2ecf20Sopenharmony_ci list_move(&priv->filters, &last_filter->next); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->filters_lock); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci list_for_each_entry_safe(filter, tmp, &del_list, next) 4718c2ecf20Sopenharmony_ci mlx4_en_filter_free(filter); 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci#endif 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int mlx4_en_vlan_rx_add_vid(struct net_device *dev, 4768c2ecf20Sopenharmony_ci __be16 proto, u16 vid) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 4798c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 4808c2ecf20Sopenharmony_ci int err; 4818c2ecf20Sopenharmony_ci int idx; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci en_dbg(HW, priv, "adding VLAN:%d\n", vid); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci set_bit(vid, priv->active_vlans); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* Add VID to port VLAN filter */ 4888c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 4898c2ecf20Sopenharmony_ci if (mdev->device_up && priv->port_up) { 4908c2ecf20Sopenharmony_ci err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); 4918c2ecf20Sopenharmony_ci if (err) { 4928c2ecf20Sopenharmony_ci en_err(priv, "Failed configuring VLAN filter\n"); 4938c2ecf20Sopenharmony_ci goto out; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci err = mlx4_register_vlan(mdev->dev, priv->port, vid, &idx); 4978c2ecf20Sopenharmony_ci if (err) 4988c2ecf20Sopenharmony_ci en_dbg(HW, priv, "Failed adding vlan %d\n", vid); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ciout: 5018c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 5028c2ecf20Sopenharmony_ci return err; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, 5068c2ecf20Sopenharmony_ci __be16 proto, u16 vid) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 5098c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 5108c2ecf20Sopenharmony_ci int err = 0; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci en_dbg(HW, priv, "Killing VID:%d\n", vid); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci clear_bit(vid, priv->active_vlans); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* Remove VID from port VLAN filter */ 5178c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 5188c2ecf20Sopenharmony_ci mlx4_unregister_vlan(mdev->dev, priv->port, vid); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (mdev->device_up && priv->port_up) { 5218c2ecf20Sopenharmony_ci err = mlx4_SET_VLAN_FLTR(mdev->dev, priv); 5228c2ecf20Sopenharmony_ci if (err) 5238c2ecf20Sopenharmony_ci en_err(priv, "Failed configuring VLAN filter\n"); 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return err; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci int i; 5338c2ecf20Sopenharmony_ci for (i = ETH_ALEN - 1; i >= 0; --i) { 5348c2ecf20Sopenharmony_ci dst_mac[i] = src_mac & 0xff; 5358c2ecf20Sopenharmony_ci src_mac >>= 8; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci memset(&dst_mac[ETH_ALEN], 0, 2); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int mlx4_en_tunnel_steer_add(struct mlx4_en_priv *priv, unsigned char *addr, 5428c2ecf20Sopenharmony_ci int qpn, u64 *reg_id) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci int err; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN || 5478c2ecf20Sopenharmony_ci priv->mdev->dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC) 5488c2ecf20Sopenharmony_ci return 0; /* do nothing */ 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci err = mlx4_tunnel_steer_add(priv->mdev->dev, addr, priv->port, qpn, 5518c2ecf20Sopenharmony_ci MLX4_DOMAIN_NIC, reg_id); 5528c2ecf20Sopenharmony_ci if (err) { 5538c2ecf20Sopenharmony_ci en_err(priv, "failed to add vxlan steering rule, err %d\n", err); 5548c2ecf20Sopenharmony_ci return err; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "added vxlan steering rule, mac %pM reg_id %llx\n", addr, *reg_id); 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistatic int mlx4_en_uc_steer_add(struct mlx4_en_priv *priv, 5628c2ecf20Sopenharmony_ci unsigned char *mac, int *qpn, u64 *reg_id) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 5658c2ecf20Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 5668c2ecf20Sopenharmony_ci int err; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci switch (dev->caps.steering_mode) { 5698c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_B0: { 5708c2ecf20Sopenharmony_ci struct mlx4_qp qp; 5718c2ecf20Sopenharmony_ci u8 gid[16] = {0}; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci qp.qpn = *qpn; 5748c2ecf20Sopenharmony_ci memcpy(&gid[10], mac, ETH_ALEN); 5758c2ecf20Sopenharmony_ci gid[5] = priv->port; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci err = mlx4_unicast_attach(dev, &qp, gid, 0, MLX4_PROT_ETH); 5788c2ecf20Sopenharmony_ci break; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: { 5818c2ecf20Sopenharmony_ci struct mlx4_spec_list spec_eth = { {NULL} }; 5828c2ecf20Sopenharmony_ci __be64 mac_mask = cpu_to_be64(MLX4_MAC_MASK << 16); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci struct mlx4_net_trans_rule rule = { 5858c2ecf20Sopenharmony_ci .queue_mode = MLX4_NET_TRANS_Q_FIFO, 5868c2ecf20Sopenharmony_ci .exclusive = 0, 5878c2ecf20Sopenharmony_ci .allow_loopback = 1, 5888c2ecf20Sopenharmony_ci .promisc_mode = MLX4_FS_REGULAR, 5898c2ecf20Sopenharmony_ci .priority = MLX4_DOMAIN_NIC, 5908c2ecf20Sopenharmony_ci }; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci rule.port = priv->port; 5938c2ecf20Sopenharmony_ci rule.qpn = *qpn; 5948c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rule.list); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci spec_eth.id = MLX4_NET_TRANS_RULE_ID_ETH; 5978c2ecf20Sopenharmony_ci memcpy(spec_eth.eth.dst_mac, mac, ETH_ALEN); 5988c2ecf20Sopenharmony_ci memcpy(spec_eth.eth.dst_mac_msk, &mac_mask, ETH_ALEN); 5998c2ecf20Sopenharmony_ci list_add_tail(&spec_eth.list, &rule.list); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci err = mlx4_flow_attach(dev, &rule, reg_id); 6028c2ecf20Sopenharmony_ci break; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci default: 6058c2ecf20Sopenharmony_ci return -EINVAL; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci if (err) 6088c2ecf20Sopenharmony_ci en_warn(priv, "Failed Attaching Unicast\n"); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return err; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic void mlx4_en_uc_steer_release(struct mlx4_en_priv *priv, 6148c2ecf20Sopenharmony_ci unsigned char *mac, int qpn, u64 reg_id) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 6178c2ecf20Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci switch (dev->caps.steering_mode) { 6208c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_B0: { 6218c2ecf20Sopenharmony_ci struct mlx4_qp qp; 6228c2ecf20Sopenharmony_ci u8 gid[16] = {0}; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci qp.qpn = qpn; 6258c2ecf20Sopenharmony_ci memcpy(&gid[10], mac, ETH_ALEN); 6268c2ecf20Sopenharmony_ci gid[5] = priv->port; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci mlx4_unicast_detach(dev, &qp, gid, MLX4_PROT_ETH); 6298c2ecf20Sopenharmony_ci break; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: { 6328c2ecf20Sopenharmony_ci mlx4_flow_detach(dev, reg_id); 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci default: 6368c2ecf20Sopenharmony_ci en_err(priv, "Invalid steering mode.\n"); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic int mlx4_en_get_qp(struct mlx4_en_priv *priv) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 6438c2ecf20Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 6448c2ecf20Sopenharmony_ci int index = 0; 6458c2ecf20Sopenharmony_ci int err = 0; 6468c2ecf20Sopenharmony_ci int *qpn = &priv->base_qpn; 6478c2ecf20Sopenharmony_ci u64 mac = mlx4_mac_to_u64(priv->dev->dev_addr); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Registering MAC: %pM for adding\n", 6508c2ecf20Sopenharmony_ci priv->dev->dev_addr); 6518c2ecf20Sopenharmony_ci index = mlx4_register_mac(dev, priv->port, mac); 6528c2ecf20Sopenharmony_ci if (index < 0) { 6538c2ecf20Sopenharmony_ci err = index; 6548c2ecf20Sopenharmony_ci en_err(priv, "Failed adding MAC: %pM\n", 6558c2ecf20Sopenharmony_ci priv->dev->dev_addr); 6568c2ecf20Sopenharmony_ci return err; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci en_info(priv, "Steering Mode %d\n", dev->caps.steering_mode); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { 6628c2ecf20Sopenharmony_ci int base_qpn = mlx4_get_base_qpn(dev, priv->port); 6638c2ecf20Sopenharmony_ci *qpn = base_qpn + index; 6648c2ecf20Sopenharmony_ci return 0; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci err = mlx4_qp_reserve_range(dev, 1, 1, qpn, MLX4_RESERVE_A0_QP, 6688c2ecf20Sopenharmony_ci MLX4_RES_USAGE_DRIVER); 6698c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Reserved qp %d\n", *qpn); 6708c2ecf20Sopenharmony_ci if (err) { 6718c2ecf20Sopenharmony_ci en_err(priv, "Failed to reserve qp for mac registration\n"); 6728c2ecf20Sopenharmony_ci mlx4_unregister_mac(dev, priv->port, mac); 6738c2ecf20Sopenharmony_ci return err; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci return 0; 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic void mlx4_en_put_qp(struct mlx4_en_priv *priv) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 6828c2ecf20Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 6838c2ecf20Sopenharmony_ci int qpn = priv->base_qpn; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { 6868c2ecf20Sopenharmony_ci u64 mac = mlx4_mac_to_u64(priv->dev->dev_addr); 6878c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", 6888c2ecf20Sopenharmony_ci priv->dev->dev_addr); 6898c2ecf20Sopenharmony_ci mlx4_unregister_mac(dev, priv->port, mac); 6908c2ecf20Sopenharmony_ci } else { 6918c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Releasing qp: port %d, qpn %d\n", 6928c2ecf20Sopenharmony_ci priv->port, qpn); 6938c2ecf20Sopenharmony_ci mlx4_qp_release_range(dev, qpn, 1); 6948c2ecf20Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn, 6998c2ecf20Sopenharmony_ci unsigned char *new_mac, unsigned char *prev_mac) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 7028c2ecf20Sopenharmony_ci struct mlx4_dev *dev = mdev->dev; 7038c2ecf20Sopenharmony_ci int err = 0; 7048c2ecf20Sopenharmony_ci u64 new_mac_u64 = mlx4_mac_to_u64(new_mac); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { 7078c2ecf20Sopenharmony_ci struct hlist_head *bucket; 7088c2ecf20Sopenharmony_ci unsigned int mac_hash; 7098c2ecf20Sopenharmony_ci struct mlx4_mac_entry *entry; 7108c2ecf20Sopenharmony_ci struct hlist_node *tmp; 7118c2ecf20Sopenharmony_ci u64 prev_mac_u64 = mlx4_mac_to_u64(prev_mac); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]]; 7148c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { 7158c2ecf20Sopenharmony_ci if (ether_addr_equal_64bits(entry->mac, prev_mac)) { 7168c2ecf20Sopenharmony_ci mlx4_en_uc_steer_release(priv, entry->mac, 7178c2ecf20Sopenharmony_ci qpn, entry->reg_id); 7188c2ecf20Sopenharmony_ci mlx4_unregister_mac(dev, priv->port, 7198c2ecf20Sopenharmony_ci prev_mac_u64); 7208c2ecf20Sopenharmony_ci hlist_del_rcu(&entry->hlist); 7218c2ecf20Sopenharmony_ci synchronize_rcu(); 7228c2ecf20Sopenharmony_ci memcpy(entry->mac, new_mac, ETH_ALEN); 7238c2ecf20Sopenharmony_ci entry->reg_id = 0; 7248c2ecf20Sopenharmony_ci mac_hash = new_mac[MLX4_EN_MAC_HASH_IDX]; 7258c2ecf20Sopenharmony_ci hlist_add_head_rcu(&entry->hlist, 7268c2ecf20Sopenharmony_ci &priv->mac_hash[mac_hash]); 7278c2ecf20Sopenharmony_ci mlx4_register_mac(dev, priv->port, new_mac_u64); 7288c2ecf20Sopenharmony_ci err = mlx4_en_uc_steer_add(priv, new_mac, 7298c2ecf20Sopenharmony_ci &qpn, 7308c2ecf20Sopenharmony_ci &entry->reg_id); 7318c2ecf20Sopenharmony_ci if (err) 7328c2ecf20Sopenharmony_ci return err; 7338c2ecf20Sopenharmony_ci if (priv->tunnel_reg_id) { 7348c2ecf20Sopenharmony_ci mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id); 7358c2ecf20Sopenharmony_ci priv->tunnel_reg_id = 0; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci err = mlx4_en_tunnel_steer_add(priv, new_mac, qpn, 7388c2ecf20Sopenharmony_ci &priv->tunnel_reg_id); 7398c2ecf20Sopenharmony_ci return err; 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci return -EINVAL; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64); 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic void mlx4_en_update_user_mac(struct mlx4_en_priv *priv, 7498c2ecf20Sopenharmony_ci unsigned char new_mac[ETH_ALEN + 2]) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 7528c2ecf20Sopenharmony_ci int err; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_USER_MAC_EN)) 7558c2ecf20Sopenharmony_ci return; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_user_mac(mdev->dev, priv->port, new_mac); 7588c2ecf20Sopenharmony_ci if (err) 7598c2ecf20Sopenharmony_ci en_err(priv, "Failed to pass user MAC(%pM) to Firmware for port %d, with error %d\n", 7608c2ecf20Sopenharmony_ci new_mac, priv->port, err); 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic int mlx4_en_do_set_mac(struct mlx4_en_priv *priv, 7648c2ecf20Sopenharmony_ci unsigned char new_mac[ETH_ALEN + 2]) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci int err = 0; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (priv->port_up) { 7698c2ecf20Sopenharmony_ci /* Remove old MAC and insert the new one */ 7708c2ecf20Sopenharmony_ci err = mlx4_en_replace_mac(priv, priv->base_qpn, 7718c2ecf20Sopenharmony_ci new_mac, priv->current_mac); 7728c2ecf20Sopenharmony_ci if (err) 7738c2ecf20Sopenharmony_ci en_err(priv, "Failed changing HW MAC address\n"); 7748c2ecf20Sopenharmony_ci } else 7758c2ecf20Sopenharmony_ci en_dbg(HW, priv, "Port is down while registering mac, exiting...\n"); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (!err) 7788c2ecf20Sopenharmony_ci memcpy(priv->current_mac, new_mac, sizeof(priv->current_mac)); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return err; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic int mlx4_en_set_mac(struct net_device *dev, void *addr) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 7868c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 7878c2ecf20Sopenharmony_ci struct sockaddr *saddr = addr; 7888c2ecf20Sopenharmony_ci unsigned char new_mac[ETH_ALEN + 2]; 7898c2ecf20Sopenharmony_ci int err; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(saddr->sa_data)) 7928c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 7958c2ecf20Sopenharmony_ci memcpy(new_mac, saddr->sa_data, ETH_ALEN); 7968c2ecf20Sopenharmony_ci err = mlx4_en_do_set_mac(priv, new_mac); 7978c2ecf20Sopenharmony_ci if (err) 7988c2ecf20Sopenharmony_ci goto out; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN); 8018c2ecf20Sopenharmony_ci mlx4_en_update_user_mac(priv, new_mac); 8028c2ecf20Sopenharmony_ciout: 8038c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return err; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic void mlx4_en_clear_list(struct net_device *dev) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 8118c2ecf20Sopenharmony_ci struct mlx4_en_mc_list *tmp, *mc_to_del; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci list_for_each_entry_safe(mc_to_del, tmp, &priv->mc_list, list) { 8148c2ecf20Sopenharmony_ci list_del(&mc_to_del->list); 8158c2ecf20Sopenharmony_ci kfree(mc_to_del); 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic void mlx4_en_cache_mclist(struct net_device *dev) 8208c2ecf20Sopenharmony_ci{ 8218c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 8228c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 8238c2ecf20Sopenharmony_ci struct mlx4_en_mc_list *tmp; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci mlx4_en_clear_list(dev); 8268c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 8278c2ecf20Sopenharmony_ci tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC); 8288c2ecf20Sopenharmony_ci if (!tmp) { 8298c2ecf20Sopenharmony_ci mlx4_en_clear_list(dev); 8308c2ecf20Sopenharmony_ci return; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci memcpy(tmp->addr, ha->addr, ETH_ALEN); 8338c2ecf20Sopenharmony_ci list_add_tail(&tmp->list, &priv->mc_list); 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic void update_mclist_flags(struct mlx4_en_priv *priv, 8388c2ecf20Sopenharmony_ci struct list_head *dst, 8398c2ecf20Sopenharmony_ci struct list_head *src) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci struct mlx4_en_mc_list *dst_tmp, *src_tmp, *new_mc; 8428c2ecf20Sopenharmony_ci bool found; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* Find all the entries that should be removed from dst, 8458c2ecf20Sopenharmony_ci * These are the entries that are not found in src 8468c2ecf20Sopenharmony_ci */ 8478c2ecf20Sopenharmony_ci list_for_each_entry(dst_tmp, dst, list) { 8488c2ecf20Sopenharmony_ci found = false; 8498c2ecf20Sopenharmony_ci list_for_each_entry(src_tmp, src, list) { 8508c2ecf20Sopenharmony_ci if (ether_addr_equal(dst_tmp->addr, src_tmp->addr)) { 8518c2ecf20Sopenharmony_ci found = true; 8528c2ecf20Sopenharmony_ci break; 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci if (!found) 8568c2ecf20Sopenharmony_ci dst_tmp->action = MCLIST_REM; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* Add entries that exist in src but not in dst 8608c2ecf20Sopenharmony_ci * mark them as need to add 8618c2ecf20Sopenharmony_ci */ 8628c2ecf20Sopenharmony_ci list_for_each_entry(src_tmp, src, list) { 8638c2ecf20Sopenharmony_ci found = false; 8648c2ecf20Sopenharmony_ci list_for_each_entry(dst_tmp, dst, list) { 8658c2ecf20Sopenharmony_ci if (ether_addr_equal(dst_tmp->addr, src_tmp->addr)) { 8668c2ecf20Sopenharmony_ci dst_tmp->action = MCLIST_NONE; 8678c2ecf20Sopenharmony_ci found = true; 8688c2ecf20Sopenharmony_ci break; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci if (!found) { 8728c2ecf20Sopenharmony_ci new_mc = kmemdup(src_tmp, 8738c2ecf20Sopenharmony_ci sizeof(struct mlx4_en_mc_list), 8748c2ecf20Sopenharmony_ci GFP_KERNEL); 8758c2ecf20Sopenharmony_ci if (!new_mc) 8768c2ecf20Sopenharmony_ci return; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci new_mc->action = MCLIST_ADD; 8798c2ecf20Sopenharmony_ci list_add_tail(&new_mc->list, dst); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic void mlx4_en_set_rx_mode(struct net_device *dev) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci if (!priv->port_up) 8898c2ecf20Sopenharmony_ci return; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci queue_work(priv->mdev->workqueue, &priv->rx_mode_task); 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic void mlx4_en_set_promisc_mode(struct mlx4_en_priv *priv, 8958c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci int err = 0; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) { 9008c2ecf20Sopenharmony_ci if (netif_msg_rx_status(priv)) 9018c2ecf20Sopenharmony_ci en_warn(priv, "Entering promiscuous mode\n"); 9028c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_PROMISC; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci /* Enable promiscouos mode */ 9058c2ecf20Sopenharmony_ci switch (mdev->dev->caps.steering_mode) { 9068c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 9078c2ecf20Sopenharmony_ci err = mlx4_flow_steer_promisc_add(mdev->dev, 9088c2ecf20Sopenharmony_ci priv->port, 9098c2ecf20Sopenharmony_ci priv->base_qpn, 9108c2ecf20Sopenharmony_ci MLX4_FS_ALL_DEFAULT); 9118c2ecf20Sopenharmony_ci if (err) 9128c2ecf20Sopenharmony_ci en_err(priv, "Failed enabling promiscuous mode\n"); 9138c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_B0: 9178c2ecf20Sopenharmony_ci err = mlx4_unicast_promisc_add(mdev->dev, 9188c2ecf20Sopenharmony_ci priv->base_qpn, 9198c2ecf20Sopenharmony_ci priv->port); 9208c2ecf20Sopenharmony_ci if (err) 9218c2ecf20Sopenharmony_ci en_err(priv, "Failed enabling unicast promiscuous mode\n"); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* Add the default qp number as multicast 9248c2ecf20Sopenharmony_ci * promisc 9258c2ecf20Sopenharmony_ci */ 9268c2ecf20Sopenharmony_ci if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { 9278c2ecf20Sopenharmony_ci err = mlx4_multicast_promisc_add(mdev->dev, 9288c2ecf20Sopenharmony_ci priv->base_qpn, 9298c2ecf20Sopenharmony_ci priv->port); 9308c2ecf20Sopenharmony_ci if (err) 9318c2ecf20Sopenharmony_ci en_err(priv, "Failed enabling multicast promiscuous mode\n"); 9328c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci break; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_A0: 9378c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_qpn_calc(mdev->dev, 9388c2ecf20Sopenharmony_ci priv->port, 9398c2ecf20Sopenharmony_ci priv->base_qpn, 9408c2ecf20Sopenharmony_ci 1); 9418c2ecf20Sopenharmony_ci if (err) 9428c2ecf20Sopenharmony_ci en_err(priv, "Failed enabling promiscuous mode\n"); 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci /* Disable port multicast filter (unconditionally) */ 9478c2ecf20Sopenharmony_ci err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 9488c2ecf20Sopenharmony_ci 0, MLX4_MCAST_DISABLE); 9498c2ecf20Sopenharmony_ci if (err) 9508c2ecf20Sopenharmony_ci en_err(priv, "Failed disabling multicast filter\n"); 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci} 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_cistatic void mlx4_en_clear_promisc_mode(struct mlx4_en_priv *priv, 9558c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci int err = 0; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (netif_msg_rx_status(priv)) 9608c2ecf20Sopenharmony_ci en_warn(priv, "Leaving promiscuous mode\n"); 9618c2ecf20Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_PROMISC; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* Disable promiscouos mode */ 9648c2ecf20Sopenharmony_ci switch (mdev->dev->caps.steering_mode) { 9658c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 9668c2ecf20Sopenharmony_ci err = mlx4_flow_steer_promisc_remove(mdev->dev, 9678c2ecf20Sopenharmony_ci priv->port, 9688c2ecf20Sopenharmony_ci MLX4_FS_ALL_DEFAULT); 9698c2ecf20Sopenharmony_ci if (err) 9708c2ecf20Sopenharmony_ci en_err(priv, "Failed disabling promiscuous mode\n"); 9718c2ecf20Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 9728c2ecf20Sopenharmony_ci break; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_B0: 9758c2ecf20Sopenharmony_ci err = mlx4_unicast_promisc_remove(mdev->dev, 9768c2ecf20Sopenharmony_ci priv->base_qpn, 9778c2ecf20Sopenharmony_ci priv->port); 9788c2ecf20Sopenharmony_ci if (err) 9798c2ecf20Sopenharmony_ci en_err(priv, "Failed disabling unicast promiscuous mode\n"); 9808c2ecf20Sopenharmony_ci /* Disable Multicast promisc */ 9818c2ecf20Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 9828c2ecf20Sopenharmony_ci err = mlx4_multicast_promisc_remove(mdev->dev, 9838c2ecf20Sopenharmony_ci priv->base_qpn, 9848c2ecf20Sopenharmony_ci priv->port); 9858c2ecf20Sopenharmony_ci if (err) 9868c2ecf20Sopenharmony_ci en_err(priv, "Failed disabling multicast promiscuous mode\n"); 9878c2ecf20Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci break; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_A0: 9928c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_qpn_calc(mdev->dev, 9938c2ecf20Sopenharmony_ci priv->port, 9948c2ecf20Sopenharmony_ci priv->base_qpn, 0); 9958c2ecf20Sopenharmony_ci if (err) 9968c2ecf20Sopenharmony_ci en_err(priv, "Failed disabling promiscuous mode\n"); 9978c2ecf20Sopenharmony_ci break; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_cistatic void mlx4_en_do_multicast(struct mlx4_en_priv *priv, 10028c2ecf20Sopenharmony_ci struct net_device *dev, 10038c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci struct mlx4_en_mc_list *mclist, *tmp; 10068c2ecf20Sopenharmony_ci u64 mcast_addr = 0; 10078c2ecf20Sopenharmony_ci u8 mc_list[16] = {0}; 10088c2ecf20Sopenharmony_ci int err = 0; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* Enable/disable the multicast filter according to IFF_ALLMULTI */ 10118c2ecf20Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) { 10128c2ecf20Sopenharmony_ci err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 10138c2ecf20Sopenharmony_ci 0, MLX4_MCAST_DISABLE); 10148c2ecf20Sopenharmony_ci if (err) 10158c2ecf20Sopenharmony_ci en_err(priv, "Failed disabling multicast filter\n"); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* Add the default qp number as multicast promisc */ 10188c2ecf20Sopenharmony_ci if (!(priv->flags & MLX4_EN_FLAG_MC_PROMISC)) { 10198c2ecf20Sopenharmony_ci switch (mdev->dev->caps.steering_mode) { 10208c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 10218c2ecf20Sopenharmony_ci err = mlx4_flow_steer_promisc_add(mdev->dev, 10228c2ecf20Sopenharmony_ci priv->port, 10238c2ecf20Sopenharmony_ci priv->base_qpn, 10248c2ecf20Sopenharmony_ci MLX4_FS_MC_DEFAULT); 10258c2ecf20Sopenharmony_ci break; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_B0: 10288c2ecf20Sopenharmony_ci err = mlx4_multicast_promisc_add(mdev->dev, 10298c2ecf20Sopenharmony_ci priv->base_qpn, 10308c2ecf20Sopenharmony_ci priv->port); 10318c2ecf20Sopenharmony_ci break; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_A0: 10348c2ecf20Sopenharmony_ci break; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci if (err) 10378c2ecf20Sopenharmony_ci en_err(priv, "Failed entering multicast promisc mode\n"); 10388c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci } else { 10418c2ecf20Sopenharmony_ci /* Disable Multicast promisc */ 10428c2ecf20Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 10438c2ecf20Sopenharmony_ci switch (mdev->dev->caps.steering_mode) { 10448c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_DEVICE_MANAGED: 10458c2ecf20Sopenharmony_ci err = mlx4_flow_steer_promisc_remove(mdev->dev, 10468c2ecf20Sopenharmony_ci priv->port, 10478c2ecf20Sopenharmony_ci MLX4_FS_MC_DEFAULT); 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_B0: 10518c2ecf20Sopenharmony_ci err = mlx4_multicast_promisc_remove(mdev->dev, 10528c2ecf20Sopenharmony_ci priv->base_qpn, 10538c2ecf20Sopenharmony_ci priv->port); 10548c2ecf20Sopenharmony_ci break; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci case MLX4_STEERING_MODE_A0: 10578c2ecf20Sopenharmony_ci break; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci if (err) 10608c2ecf20Sopenharmony_ci en_err(priv, "Failed disabling multicast promiscuous mode\n"); 10618c2ecf20Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 10658c2ecf20Sopenharmony_ci 0, MLX4_MCAST_DISABLE); 10668c2ecf20Sopenharmony_ci if (err) 10678c2ecf20Sopenharmony_ci en_err(priv, "Failed disabling multicast filter\n"); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* Flush mcast filter and init it with broadcast address */ 10708c2ecf20Sopenharmony_ci mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, 10718c2ecf20Sopenharmony_ci 1, MLX4_MCAST_CONFIG); 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Update multicast list - we cache all addresses so they won't 10748c2ecf20Sopenharmony_ci * change while HW is updated holding the command semaphor */ 10758c2ecf20Sopenharmony_ci netif_addr_lock_bh(dev); 10768c2ecf20Sopenharmony_ci mlx4_en_cache_mclist(dev); 10778c2ecf20Sopenharmony_ci netif_addr_unlock_bh(dev); 10788c2ecf20Sopenharmony_ci list_for_each_entry(mclist, &priv->mc_list, list) { 10798c2ecf20Sopenharmony_ci mcast_addr = mlx4_mac_to_u64(mclist->addr); 10808c2ecf20Sopenharmony_ci mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 10818c2ecf20Sopenharmony_ci mcast_addr, 0, MLX4_MCAST_CONFIG); 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 10848c2ecf20Sopenharmony_ci 0, MLX4_MCAST_ENABLE); 10858c2ecf20Sopenharmony_ci if (err) 10868c2ecf20Sopenharmony_ci en_err(priv, "Failed enabling multicast filter\n"); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci update_mclist_flags(priv, &priv->curr_list, &priv->mc_list); 10898c2ecf20Sopenharmony_ci list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { 10908c2ecf20Sopenharmony_ci if (mclist->action == MCLIST_REM) { 10918c2ecf20Sopenharmony_ci /* detach this address and delete from list */ 10928c2ecf20Sopenharmony_ci memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 10938c2ecf20Sopenharmony_ci mc_list[5] = priv->port; 10948c2ecf20Sopenharmony_ci err = mlx4_multicast_detach(mdev->dev, 10958c2ecf20Sopenharmony_ci priv->rss_map.indir_qp, 10968c2ecf20Sopenharmony_ci mc_list, 10978c2ecf20Sopenharmony_ci MLX4_PROT_ETH, 10988c2ecf20Sopenharmony_ci mclist->reg_id); 10998c2ecf20Sopenharmony_ci if (err) 11008c2ecf20Sopenharmony_ci en_err(priv, "Fail to detach multicast address\n"); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if (mclist->tunnel_reg_id) { 11038c2ecf20Sopenharmony_ci err = mlx4_flow_detach(priv->mdev->dev, mclist->tunnel_reg_id); 11048c2ecf20Sopenharmony_ci if (err) 11058c2ecf20Sopenharmony_ci en_err(priv, "Failed to detach multicast address\n"); 11068c2ecf20Sopenharmony_ci } 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci /* remove from list */ 11098c2ecf20Sopenharmony_ci list_del(&mclist->list); 11108c2ecf20Sopenharmony_ci kfree(mclist); 11118c2ecf20Sopenharmony_ci } else if (mclist->action == MCLIST_ADD) { 11128c2ecf20Sopenharmony_ci /* attach the address */ 11138c2ecf20Sopenharmony_ci memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 11148c2ecf20Sopenharmony_ci /* needed for B0 steering support */ 11158c2ecf20Sopenharmony_ci mc_list[5] = priv->port; 11168c2ecf20Sopenharmony_ci err = mlx4_multicast_attach(mdev->dev, 11178c2ecf20Sopenharmony_ci priv->rss_map.indir_qp, 11188c2ecf20Sopenharmony_ci mc_list, 11198c2ecf20Sopenharmony_ci priv->port, 0, 11208c2ecf20Sopenharmony_ci MLX4_PROT_ETH, 11218c2ecf20Sopenharmony_ci &mclist->reg_id); 11228c2ecf20Sopenharmony_ci if (err) 11238c2ecf20Sopenharmony_ci en_err(priv, "Fail to attach multicast address\n"); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci err = mlx4_en_tunnel_steer_add(priv, &mc_list[10], priv->base_qpn, 11268c2ecf20Sopenharmony_ci &mclist->tunnel_reg_id); 11278c2ecf20Sopenharmony_ci if (err) 11288c2ecf20Sopenharmony_ci en_err(priv, "Failed to attach multicast address\n"); 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv, 11358c2ecf20Sopenharmony_ci struct net_device *dev, 11368c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 11398c2ecf20Sopenharmony_ci struct mlx4_mac_entry *entry; 11408c2ecf20Sopenharmony_ci struct hlist_node *tmp; 11418c2ecf20Sopenharmony_ci bool found; 11428c2ecf20Sopenharmony_ci u64 mac; 11438c2ecf20Sopenharmony_ci int err = 0; 11448c2ecf20Sopenharmony_ci struct hlist_head *bucket; 11458c2ecf20Sopenharmony_ci unsigned int i; 11468c2ecf20Sopenharmony_ci int removed = 0; 11478c2ecf20Sopenharmony_ci u32 prev_flags; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* Note that we do not need to protect our mac_hash traversal with rcu, 11508c2ecf20Sopenharmony_ci * since all modification code is protected by mdev->state_lock 11518c2ecf20Sopenharmony_ci */ 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci /* find what to remove */ 11548c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { 11558c2ecf20Sopenharmony_ci bucket = &priv->mac_hash[i]; 11568c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { 11578c2ecf20Sopenharmony_ci found = false; 11588c2ecf20Sopenharmony_ci netdev_for_each_uc_addr(ha, dev) { 11598c2ecf20Sopenharmony_ci if (ether_addr_equal_64bits(entry->mac, 11608c2ecf20Sopenharmony_ci ha->addr)) { 11618c2ecf20Sopenharmony_ci found = true; 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* MAC address of the port is not in uc list */ 11678c2ecf20Sopenharmony_ci if (ether_addr_equal_64bits(entry->mac, 11688c2ecf20Sopenharmony_ci priv->current_mac)) 11698c2ecf20Sopenharmony_ci found = true; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (!found) { 11728c2ecf20Sopenharmony_ci mac = mlx4_mac_to_u64(entry->mac); 11738c2ecf20Sopenharmony_ci mlx4_en_uc_steer_release(priv, entry->mac, 11748c2ecf20Sopenharmony_ci priv->base_qpn, 11758c2ecf20Sopenharmony_ci entry->reg_id); 11768c2ecf20Sopenharmony_ci mlx4_unregister_mac(mdev->dev, priv->port, mac); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci hlist_del_rcu(&entry->hlist); 11798c2ecf20Sopenharmony_ci kfree_rcu(entry, rcu); 11808c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Removed MAC %pM on port:%d\n", 11818c2ecf20Sopenharmony_ci entry->mac, priv->port); 11828c2ecf20Sopenharmony_ci ++removed; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci /* if we didn't remove anything, there is no use in trying to add 11888c2ecf20Sopenharmony_ci * again once we are in a forced promisc mode state 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_ci if ((priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) && 0 == removed) 11918c2ecf20Sopenharmony_ci return; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci prev_flags = priv->flags; 11948c2ecf20Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* find what to add */ 11978c2ecf20Sopenharmony_ci netdev_for_each_uc_addr(ha, dev) { 11988c2ecf20Sopenharmony_ci found = false; 11998c2ecf20Sopenharmony_ci bucket = &priv->mac_hash[ha->addr[MLX4_EN_MAC_HASH_IDX]]; 12008c2ecf20Sopenharmony_ci hlist_for_each_entry(entry, bucket, hlist) { 12018c2ecf20Sopenharmony_ci if (ether_addr_equal_64bits(entry->mac, ha->addr)) { 12028c2ecf20Sopenharmony_ci found = true; 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (!found) { 12088c2ecf20Sopenharmony_ci entry = kmalloc(sizeof(*entry), GFP_KERNEL); 12098c2ecf20Sopenharmony_ci if (!entry) { 12108c2ecf20Sopenharmony_ci en_err(priv, "Failed adding MAC %pM on port:%d (out of memory)\n", 12118c2ecf20Sopenharmony_ci ha->addr, priv->port); 12128c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC; 12138c2ecf20Sopenharmony_ci break; 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci mac = mlx4_mac_to_u64(ha->addr); 12168c2ecf20Sopenharmony_ci memcpy(entry->mac, ha->addr, ETH_ALEN); 12178c2ecf20Sopenharmony_ci err = mlx4_register_mac(mdev->dev, priv->port, mac); 12188c2ecf20Sopenharmony_ci if (err < 0) { 12198c2ecf20Sopenharmony_ci en_err(priv, "Failed registering MAC %pM on port %d: %d\n", 12208c2ecf20Sopenharmony_ci ha->addr, priv->port, err); 12218c2ecf20Sopenharmony_ci kfree(entry); 12228c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC; 12238c2ecf20Sopenharmony_ci break; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci err = mlx4_en_uc_steer_add(priv, ha->addr, 12268c2ecf20Sopenharmony_ci &priv->base_qpn, 12278c2ecf20Sopenharmony_ci &entry->reg_id); 12288c2ecf20Sopenharmony_ci if (err) { 12298c2ecf20Sopenharmony_ci en_err(priv, "Failed adding MAC %pM on port %d: %d\n", 12308c2ecf20Sopenharmony_ci ha->addr, priv->port, err); 12318c2ecf20Sopenharmony_ci mlx4_unregister_mac(mdev->dev, priv->port, mac); 12328c2ecf20Sopenharmony_ci kfree(entry); 12338c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC; 12348c2ecf20Sopenharmony_ci break; 12358c2ecf20Sopenharmony_ci } else { 12368c2ecf20Sopenharmony_ci unsigned int mac_hash; 12378c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Added MAC %pM on port:%d\n", 12388c2ecf20Sopenharmony_ci ha->addr, priv->port); 12398c2ecf20Sopenharmony_ci mac_hash = ha->addr[MLX4_EN_MAC_HASH_IDX]; 12408c2ecf20Sopenharmony_ci bucket = &priv->mac_hash[mac_hash]; 12418c2ecf20Sopenharmony_ci hlist_add_head_rcu(&entry->hlist, bucket); 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) { 12478c2ecf20Sopenharmony_ci en_warn(priv, "Forcing promiscuous mode on port:%d\n", 12488c2ecf20Sopenharmony_ci priv->port); 12498c2ecf20Sopenharmony_ci } else if (prev_flags & MLX4_EN_FLAG_FORCE_PROMISC) { 12508c2ecf20Sopenharmony_ci en_warn(priv, "Stop forcing promiscuous mode on port:%d\n", 12518c2ecf20Sopenharmony_ci priv->port); 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic void mlx4_en_do_set_rx_mode(struct work_struct *work) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 12588c2ecf20Sopenharmony_ci rx_mode_task); 12598c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 12608c2ecf20Sopenharmony_ci struct net_device *dev = priv->dev; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 12638c2ecf20Sopenharmony_ci if (!mdev->device_up) { 12648c2ecf20Sopenharmony_ci en_dbg(HW, priv, "Card is not up, ignoring rx mode change.\n"); 12658c2ecf20Sopenharmony_ci goto out; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci if (!priv->port_up) { 12688c2ecf20Sopenharmony_ci en_dbg(HW, priv, "Port is down, ignoring rx mode change.\n"); 12698c2ecf20Sopenharmony_ci goto out; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci if (!netif_carrier_ok(dev)) { 12738c2ecf20Sopenharmony_ci if (!mlx4_en_QUERY_PORT(mdev, priv->port)) { 12748c2ecf20Sopenharmony_ci if (priv->port_state.link_state) { 12758c2ecf20Sopenharmony_ci priv->last_link_state = MLX4_DEV_EVENT_PORT_UP; 12768c2ecf20Sopenharmony_ci netif_carrier_on(dev); 12778c2ecf20Sopenharmony_ci en_dbg(LINK, priv, "Link Up\n"); 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (dev->priv_flags & IFF_UNICAST_FLT) 12838c2ecf20Sopenharmony_ci mlx4_en_do_uc_filter(priv, dev, mdev); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* Promsicuous mode: disable all filters */ 12868c2ecf20Sopenharmony_ci if ((dev->flags & IFF_PROMISC) || 12878c2ecf20Sopenharmony_ci (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) { 12888c2ecf20Sopenharmony_ci mlx4_en_set_promisc_mode(priv, mdev); 12898c2ecf20Sopenharmony_ci goto out; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* Not in promiscuous mode */ 12938c2ecf20Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_PROMISC) 12948c2ecf20Sopenharmony_ci mlx4_en_clear_promisc_mode(priv, mdev); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci mlx4_en_do_multicast(priv, dev, mdev); 12978c2ecf20Sopenharmony_ciout: 12988c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_cistatic int mlx4_en_set_rss_steer_rules(struct mlx4_en_priv *priv) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci u64 reg_id; 13048c2ecf20Sopenharmony_ci int err = 0; 13058c2ecf20Sopenharmony_ci int *qpn = &priv->base_qpn; 13068c2ecf20Sopenharmony_ci struct mlx4_mac_entry *entry; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci err = mlx4_en_uc_steer_add(priv, priv->dev->dev_addr, qpn, ®_id); 13098c2ecf20Sopenharmony_ci if (err) 13108c2ecf20Sopenharmony_ci return err; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci err = mlx4_en_tunnel_steer_add(priv, priv->dev->dev_addr, *qpn, 13138c2ecf20Sopenharmony_ci &priv->tunnel_reg_id); 13148c2ecf20Sopenharmony_ci if (err) 13158c2ecf20Sopenharmony_ci goto tunnel_err; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci entry = kmalloc(sizeof(*entry), GFP_KERNEL); 13188c2ecf20Sopenharmony_ci if (!entry) { 13198c2ecf20Sopenharmony_ci err = -ENOMEM; 13208c2ecf20Sopenharmony_ci goto alloc_err; 13218c2ecf20Sopenharmony_ci } 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac)); 13248c2ecf20Sopenharmony_ci memcpy(priv->current_mac, entry->mac, sizeof(priv->current_mac)); 13258c2ecf20Sopenharmony_ci entry->reg_id = reg_id; 13268c2ecf20Sopenharmony_ci hlist_add_head_rcu(&entry->hlist, 13278c2ecf20Sopenharmony_ci &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci return 0; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cialloc_err: 13328c2ecf20Sopenharmony_ci if (priv->tunnel_reg_id) 13338c2ecf20Sopenharmony_ci mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_citunnel_err: 13368c2ecf20Sopenharmony_ci mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id); 13378c2ecf20Sopenharmony_ci return err; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic void mlx4_en_delete_rss_steer_rules(struct mlx4_en_priv *priv) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci u64 mac; 13438c2ecf20Sopenharmony_ci unsigned int i; 13448c2ecf20Sopenharmony_ci int qpn = priv->base_qpn; 13458c2ecf20Sopenharmony_ci struct hlist_head *bucket; 13468c2ecf20Sopenharmony_ci struct hlist_node *tmp; 13478c2ecf20Sopenharmony_ci struct mlx4_mac_entry *entry; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { 13508c2ecf20Sopenharmony_ci bucket = &priv->mac_hash[i]; 13518c2ecf20Sopenharmony_ci hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { 13528c2ecf20Sopenharmony_ci mac = mlx4_mac_to_u64(entry->mac); 13538c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Registering MAC:%pM for deleting\n", 13548c2ecf20Sopenharmony_ci entry->mac); 13558c2ecf20Sopenharmony_ci mlx4_en_uc_steer_release(priv, entry->mac, 13568c2ecf20Sopenharmony_ci qpn, entry->reg_id); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci mlx4_unregister_mac(priv->mdev->dev, priv->port, mac); 13598c2ecf20Sopenharmony_ci hlist_del_rcu(&entry->hlist); 13608c2ecf20Sopenharmony_ci kfree_rcu(entry, rcu); 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci if (priv->tunnel_reg_id) { 13658c2ecf20Sopenharmony_ci mlx4_flow_detach(priv->mdev->dev, priv->tunnel_reg_id); 13668c2ecf20Sopenharmony_ci priv->tunnel_reg_id = 0; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci} 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_cistatic void mlx4_en_tx_timeout(struct net_device *dev, unsigned int txqueue) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 13738c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 13748c2ecf20Sopenharmony_ci struct mlx4_en_tx_ring *tx_ring = priv->tx_ring[TX][txqueue]; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (netif_msg_timer(priv)) 13778c2ecf20Sopenharmony_ci en_warn(priv, "Tx timeout called on port:%d\n", priv->port); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci en_warn(priv, "TX timeout on queue: %d, QP: 0x%x, CQ: 0x%x, Cons: 0x%x, Prod: 0x%x\n", 13808c2ecf20Sopenharmony_ci txqueue, tx_ring->qpn, tx_ring->sp_cqn, 13818c2ecf20Sopenharmony_ci tx_ring->cons, tx_ring->prod); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci priv->port_stats.tx_timeout++; 13848c2ecf20Sopenharmony_ci if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state)) { 13858c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Scheduling port restart\n"); 13868c2ecf20Sopenharmony_ci queue_work(mdev->workqueue, &priv->restart_task); 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci} 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_cistatic void 13928c2ecf20Sopenharmony_cimlx4_en_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci spin_lock_bh(&priv->stats_lock); 13978c2ecf20Sopenharmony_ci mlx4_en_fold_software_stats(dev); 13988c2ecf20Sopenharmony_ci netdev_stats_to_stats64(stats, &dev->stats); 13998c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->stats_lock); 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct mlx4_en_cq *cq; 14058c2ecf20Sopenharmony_ci int i, t; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci /* If we haven't received a specific coalescing setting 14088c2ecf20Sopenharmony_ci * (module param), we set the moderation parameters as follows: 14098c2ecf20Sopenharmony_ci * - moder_cnt is set to the number of mtu sized packets to 14108c2ecf20Sopenharmony_ci * satisfy our coalescing target. 14118c2ecf20Sopenharmony_ci * - moder_time is set to a fixed value. 14128c2ecf20Sopenharmony_ci */ 14138c2ecf20Sopenharmony_ci priv->rx_frames = MLX4_EN_RX_COAL_TARGET; 14148c2ecf20Sopenharmony_ci priv->rx_usecs = MLX4_EN_RX_COAL_TIME; 14158c2ecf20Sopenharmony_ci priv->tx_frames = MLX4_EN_TX_COAL_PKTS; 14168c2ecf20Sopenharmony_ci priv->tx_usecs = MLX4_EN_TX_COAL_TIME; 14178c2ecf20Sopenharmony_ci en_dbg(INTR, priv, "Default coalescing params for mtu:%d - rx_frames:%d rx_usecs:%d\n", 14188c2ecf20Sopenharmony_ci priv->dev->mtu, priv->rx_frames, priv->rx_usecs); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* Setup cq moderation params */ 14218c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 14228c2ecf20Sopenharmony_ci cq = priv->rx_cq[i]; 14238c2ecf20Sopenharmony_ci cq->moder_cnt = priv->rx_frames; 14248c2ecf20Sopenharmony_ci cq->moder_time = priv->rx_usecs; 14258c2ecf20Sopenharmony_ci priv->last_moder_time[i] = MLX4_EN_AUTO_CONF; 14268c2ecf20Sopenharmony_ci priv->last_moder_packets[i] = 0; 14278c2ecf20Sopenharmony_ci priv->last_moder_bytes[i] = 0; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci for (t = 0 ; t < MLX4_EN_NUM_TX_TYPES; t++) { 14318c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 14328c2ecf20Sopenharmony_ci cq = priv->tx_cq[t][i]; 14338c2ecf20Sopenharmony_ci cq->moder_cnt = priv->tx_frames; 14348c2ecf20Sopenharmony_ci cq->moder_time = priv->tx_usecs; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci /* Reset auto-moderation params */ 14398c2ecf20Sopenharmony_ci priv->pkt_rate_low = MLX4_EN_RX_RATE_LOW; 14408c2ecf20Sopenharmony_ci priv->rx_usecs_low = MLX4_EN_RX_COAL_TIME_LOW; 14418c2ecf20Sopenharmony_ci priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH; 14428c2ecf20Sopenharmony_ci priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH; 14438c2ecf20Sopenharmony_ci priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL; 14448c2ecf20Sopenharmony_ci priv->adaptive_rx_coal = 1; 14458c2ecf20Sopenharmony_ci priv->last_moder_jiffies = 0; 14468c2ecf20Sopenharmony_ci priv->last_moder_tx_packets = 0; 14478c2ecf20Sopenharmony_ci} 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_cistatic void mlx4_en_auto_moderation(struct mlx4_en_priv *priv) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci unsigned long period = (unsigned long) (jiffies - priv->last_moder_jiffies); 14528c2ecf20Sopenharmony_ci u32 pkt_rate_high, pkt_rate_low; 14538c2ecf20Sopenharmony_ci struct mlx4_en_cq *cq; 14548c2ecf20Sopenharmony_ci unsigned long packets; 14558c2ecf20Sopenharmony_ci unsigned long rate; 14568c2ecf20Sopenharmony_ci unsigned long avg_pkt_size; 14578c2ecf20Sopenharmony_ci unsigned long rx_packets; 14588c2ecf20Sopenharmony_ci unsigned long rx_bytes; 14598c2ecf20Sopenharmony_ci unsigned long rx_pkt_diff; 14608c2ecf20Sopenharmony_ci int moder_time; 14618c2ecf20Sopenharmony_ci int ring, err; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ) 14648c2ecf20Sopenharmony_ci return; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci pkt_rate_low = READ_ONCE(priv->pkt_rate_low); 14678c2ecf20Sopenharmony_ci pkt_rate_high = READ_ONCE(priv->pkt_rate_high); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci for (ring = 0; ring < priv->rx_ring_num; ring++) { 14708c2ecf20Sopenharmony_ci rx_packets = READ_ONCE(priv->rx_ring[ring]->packets); 14718c2ecf20Sopenharmony_ci rx_bytes = READ_ONCE(priv->rx_ring[ring]->bytes); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci rx_pkt_diff = rx_packets - priv->last_moder_packets[ring]; 14748c2ecf20Sopenharmony_ci packets = rx_pkt_diff; 14758c2ecf20Sopenharmony_ci rate = packets * HZ / period; 14768c2ecf20Sopenharmony_ci avg_pkt_size = packets ? (rx_bytes - 14778c2ecf20Sopenharmony_ci priv->last_moder_bytes[ring]) / packets : 0; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci /* Apply auto-moderation only when packet rate 14808c2ecf20Sopenharmony_ci * exceeds a rate that it matters */ 14818c2ecf20Sopenharmony_ci if (rate > (MLX4_EN_RX_RATE_THRESH / priv->rx_ring_num) && 14828c2ecf20Sopenharmony_ci avg_pkt_size > MLX4_EN_AVG_PKT_SMALL) { 14838c2ecf20Sopenharmony_ci if (rate <= pkt_rate_low) 14848c2ecf20Sopenharmony_ci moder_time = priv->rx_usecs_low; 14858c2ecf20Sopenharmony_ci else if (rate >= pkt_rate_high) 14868c2ecf20Sopenharmony_ci moder_time = priv->rx_usecs_high; 14878c2ecf20Sopenharmony_ci else 14888c2ecf20Sopenharmony_ci moder_time = (rate - pkt_rate_low) * 14898c2ecf20Sopenharmony_ci (priv->rx_usecs_high - priv->rx_usecs_low) / 14908c2ecf20Sopenharmony_ci (pkt_rate_high - pkt_rate_low) + 14918c2ecf20Sopenharmony_ci priv->rx_usecs_low; 14928c2ecf20Sopenharmony_ci } else { 14938c2ecf20Sopenharmony_ci moder_time = priv->rx_usecs_low; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci cq = priv->rx_cq[ring]; 14978c2ecf20Sopenharmony_ci if (moder_time != priv->last_moder_time[ring] || 14988c2ecf20Sopenharmony_ci cq->moder_cnt != priv->rx_frames) { 14998c2ecf20Sopenharmony_ci priv->last_moder_time[ring] = moder_time; 15008c2ecf20Sopenharmony_ci cq->moder_time = moder_time; 15018c2ecf20Sopenharmony_ci cq->moder_cnt = priv->rx_frames; 15028c2ecf20Sopenharmony_ci err = mlx4_en_set_cq_moder(priv, cq); 15038c2ecf20Sopenharmony_ci if (err) 15048c2ecf20Sopenharmony_ci en_err(priv, "Failed modifying moderation for cq:%d\n", 15058c2ecf20Sopenharmony_ci ring); 15068c2ecf20Sopenharmony_ci } 15078c2ecf20Sopenharmony_ci priv->last_moder_packets[ring] = rx_packets; 15088c2ecf20Sopenharmony_ci priv->last_moder_bytes[ring] = rx_bytes; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci priv->last_moder_jiffies = jiffies; 15128c2ecf20Sopenharmony_ci} 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cistatic void mlx4_en_do_get_stats(struct work_struct *work) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci struct delayed_work *delay = to_delayed_work(work); 15178c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, 15188c2ecf20Sopenharmony_ci stats_task); 15198c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 15208c2ecf20Sopenharmony_ci int err; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 15238c2ecf20Sopenharmony_ci if (mdev->device_up) { 15248c2ecf20Sopenharmony_ci if (priv->port_up) { 15258c2ecf20Sopenharmony_ci err = mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 0); 15268c2ecf20Sopenharmony_ci if (err) 15278c2ecf20Sopenharmony_ci en_dbg(HW, priv, "Could not update stats\n"); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci mlx4_en_auto_moderation(priv); 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) { 15358c2ecf20Sopenharmony_ci mlx4_en_do_set_mac(priv, priv->current_mac); 15368c2ecf20Sopenharmony_ci mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0; 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 15398c2ecf20Sopenharmony_ci} 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci/* mlx4_en_service_task - Run service task for tasks that needed to be done 15428c2ecf20Sopenharmony_ci * periodically 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_cistatic void mlx4_en_service_task(struct work_struct *work) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci struct delayed_work *delay = to_delayed_work(work); 15478c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv, 15488c2ecf20Sopenharmony_ci service_task); 15498c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 15528c2ecf20Sopenharmony_ci if (mdev->device_up) { 15538c2ecf20Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) 15548c2ecf20Sopenharmony_ci mlx4_en_ptp_overflow_check(mdev); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci mlx4_en_recover_from_oom(priv); 15578c2ecf20Sopenharmony_ci queue_delayed_work(mdev->workqueue, &priv->service_task, 15588c2ecf20Sopenharmony_ci SERVICE_TASK_DELAY); 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 15618c2ecf20Sopenharmony_ci} 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_cistatic void mlx4_en_linkstate(struct work_struct *work) 15648c2ecf20Sopenharmony_ci{ 15658c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 15668c2ecf20Sopenharmony_ci linkstate_task); 15678c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 15688c2ecf20Sopenharmony_ci int linkstate = priv->link_state; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 15718c2ecf20Sopenharmony_ci /* If observable port state changed set carrier state and 15728c2ecf20Sopenharmony_ci * report to system log */ 15738c2ecf20Sopenharmony_ci if (priv->last_link_state != linkstate) { 15748c2ecf20Sopenharmony_ci if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) { 15758c2ecf20Sopenharmony_ci en_info(priv, "Link Down\n"); 15768c2ecf20Sopenharmony_ci netif_carrier_off(priv->dev); 15778c2ecf20Sopenharmony_ci } else { 15788c2ecf20Sopenharmony_ci en_info(priv, "Link Up\n"); 15798c2ecf20Sopenharmony_ci netif_carrier_on(priv->dev); 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci priv->last_link_state = linkstate; 15838c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 15848c2ecf20Sopenharmony_ci} 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_cistatic int mlx4_en_init_affinity_hint(struct mlx4_en_priv *priv, int ring_idx) 15878c2ecf20Sopenharmony_ci{ 15888c2ecf20Sopenharmony_ci struct mlx4_en_rx_ring *ring = priv->rx_ring[ring_idx]; 15898c2ecf20Sopenharmony_ci int numa_node = priv->mdev->dev->numa_node; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci if (!zalloc_cpumask_var(&ring->affinity_mask, GFP_KERNEL)) 15928c2ecf20Sopenharmony_ci return -ENOMEM; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci cpumask_set_cpu(cpumask_local_spread(ring_idx, numa_node), 15958c2ecf20Sopenharmony_ci ring->affinity_mask); 15968c2ecf20Sopenharmony_ci return 0; 15978c2ecf20Sopenharmony_ci} 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_cistatic void mlx4_en_free_affinity_hint(struct mlx4_en_priv *priv, int ring_idx) 16008c2ecf20Sopenharmony_ci{ 16018c2ecf20Sopenharmony_ci free_cpumask_var(priv->rx_ring[ring_idx]->affinity_mask); 16028c2ecf20Sopenharmony_ci} 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_cistatic void mlx4_en_init_recycle_ring(struct mlx4_en_priv *priv, 16058c2ecf20Sopenharmony_ci int tx_ring_idx) 16068c2ecf20Sopenharmony_ci{ 16078c2ecf20Sopenharmony_ci struct mlx4_en_tx_ring *tx_ring = priv->tx_ring[TX_XDP][tx_ring_idx]; 16088c2ecf20Sopenharmony_ci int rr_index = tx_ring_idx; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci tx_ring->free_tx_desc = mlx4_en_recycle_tx_desc; 16118c2ecf20Sopenharmony_ci tx_ring->recycle_ring = priv->rx_ring[rr_index]; 16128c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Set tx_ring[%d][%d]->recycle_ring = rx_ring[%d]\n", 16138c2ecf20Sopenharmony_ci TX_XDP, tx_ring_idx, rr_index); 16148c2ecf20Sopenharmony_ci} 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ciint mlx4_en_start_port(struct net_device *dev) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 16198c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 16208c2ecf20Sopenharmony_ci struct mlx4_en_cq *cq; 16218c2ecf20Sopenharmony_ci struct mlx4_en_tx_ring *tx_ring; 16228c2ecf20Sopenharmony_ci int rx_index = 0; 16238c2ecf20Sopenharmony_ci int err = 0; 16248c2ecf20Sopenharmony_ci int i, t; 16258c2ecf20Sopenharmony_ci int j; 16268c2ecf20Sopenharmony_ci u8 mc_list[16] = {0}; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (priv->port_up) { 16298c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "start port called while port already up\n"); 16308c2ecf20Sopenharmony_ci return 0; 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->mc_list); 16348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->curr_list); 16358c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->ethtool_list); 16368c2ecf20Sopenharmony_ci memset(&priv->ethtool_rules[0], 0, 16378c2ecf20Sopenharmony_ci sizeof(struct ethtool_flow_id) * MAX_NUM_OF_FS_RULES); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* Calculate Rx buf size */ 16408c2ecf20Sopenharmony_ci dev->mtu = min(dev->mtu, priv->max_mtu); 16418c2ecf20Sopenharmony_ci mlx4_en_calc_rx_buf(dev); 16428c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci /* Configure rx cq's and rings */ 16458c2ecf20Sopenharmony_ci err = mlx4_en_activate_rx_rings(priv); 16468c2ecf20Sopenharmony_ci if (err) { 16478c2ecf20Sopenharmony_ci en_err(priv, "Failed to activate RX rings\n"); 16488c2ecf20Sopenharmony_ci return err; 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 16518c2ecf20Sopenharmony_ci cq = priv->rx_cq[i]; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci err = mlx4_en_init_affinity_hint(priv, i); 16548c2ecf20Sopenharmony_ci if (err) { 16558c2ecf20Sopenharmony_ci en_err(priv, "Failed preparing IRQ affinity hint\n"); 16568c2ecf20Sopenharmony_ci goto cq_err; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci err = mlx4_en_activate_cq(priv, cq, i); 16608c2ecf20Sopenharmony_ci if (err) { 16618c2ecf20Sopenharmony_ci en_err(priv, "Failed activating Rx CQ\n"); 16628c2ecf20Sopenharmony_ci mlx4_en_free_affinity_hint(priv, i); 16638c2ecf20Sopenharmony_ci goto cq_err; 16648c2ecf20Sopenharmony_ci } 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci for (j = 0; j < cq->size; j++) { 16678c2ecf20Sopenharmony_ci struct mlx4_cqe *cqe = NULL; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci cqe = mlx4_en_get_cqe(cq->buf, j, priv->cqe_size) + 16708c2ecf20Sopenharmony_ci priv->cqe_factor; 16718c2ecf20Sopenharmony_ci cqe->owner_sr_opcode = MLX4_CQE_OWNER_MASK; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci err = mlx4_en_set_cq_moder(priv, cq); 16758c2ecf20Sopenharmony_ci if (err) { 16768c2ecf20Sopenharmony_ci en_err(priv, "Failed setting cq moderation parameters\n"); 16778c2ecf20Sopenharmony_ci mlx4_en_deactivate_cq(priv, cq); 16788c2ecf20Sopenharmony_ci mlx4_en_free_affinity_hint(priv, i); 16798c2ecf20Sopenharmony_ci goto cq_err; 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci mlx4_en_arm_cq(priv, cq); 16828c2ecf20Sopenharmony_ci priv->rx_ring[i]->cqn = cq->mcq.cqn; 16838c2ecf20Sopenharmony_ci ++rx_index; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci /* Set qp number */ 16878c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Getting qp number for port %d\n", priv->port); 16888c2ecf20Sopenharmony_ci err = mlx4_en_get_qp(priv); 16898c2ecf20Sopenharmony_ci if (err) { 16908c2ecf20Sopenharmony_ci en_err(priv, "Failed getting eth qp\n"); 16918c2ecf20Sopenharmony_ci goto cq_err; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci mdev->mac_removed[priv->port] = 0; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci priv->counter_index = 16968c2ecf20Sopenharmony_ci mlx4_get_default_counter_index(mdev->dev, priv->port); 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci err = mlx4_en_config_rss_steer(priv); 16998c2ecf20Sopenharmony_ci if (err) { 17008c2ecf20Sopenharmony_ci en_err(priv, "Failed configuring rss steering\n"); 17018c2ecf20Sopenharmony_ci goto mac_err; 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci err = mlx4_en_create_drop_qp(priv); 17058c2ecf20Sopenharmony_ci if (err) 17068c2ecf20Sopenharmony_ci goto rss_err; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* Configure tx cq's and rings */ 17098c2ecf20Sopenharmony_ci for (t = 0 ; t < MLX4_EN_NUM_TX_TYPES; t++) { 17108c2ecf20Sopenharmony_ci u8 num_tx_rings_p_up = t == TX ? 17118c2ecf20Sopenharmony_ci priv->num_tx_rings_p_up : priv->tx_ring_num[t]; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 17148c2ecf20Sopenharmony_ci /* Configure cq */ 17158c2ecf20Sopenharmony_ci cq = priv->tx_cq[t][i]; 17168c2ecf20Sopenharmony_ci err = mlx4_en_activate_cq(priv, cq, i); 17178c2ecf20Sopenharmony_ci if (err) { 17188c2ecf20Sopenharmony_ci en_err(priv, "Failed allocating Tx CQ\n"); 17198c2ecf20Sopenharmony_ci goto tx_err; 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci err = mlx4_en_set_cq_moder(priv, cq); 17228c2ecf20Sopenharmony_ci if (err) { 17238c2ecf20Sopenharmony_ci en_err(priv, "Failed setting cq moderation parameters\n"); 17248c2ecf20Sopenharmony_ci mlx4_en_deactivate_cq(priv, cq); 17258c2ecf20Sopenharmony_ci goto tx_err; 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci en_dbg(DRV, priv, 17288c2ecf20Sopenharmony_ci "Resetting index of collapsed CQ:%d to -1\n", i); 17298c2ecf20Sopenharmony_ci cq->buf->wqe_index = cpu_to_be16(0xffff); 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci /* Configure ring */ 17328c2ecf20Sopenharmony_ci tx_ring = priv->tx_ring[t][i]; 17338c2ecf20Sopenharmony_ci err = mlx4_en_activate_tx_ring(priv, tx_ring, 17348c2ecf20Sopenharmony_ci cq->mcq.cqn, 17358c2ecf20Sopenharmony_ci i / num_tx_rings_p_up); 17368c2ecf20Sopenharmony_ci if (err) { 17378c2ecf20Sopenharmony_ci en_err(priv, "Failed allocating Tx ring\n"); 17388c2ecf20Sopenharmony_ci mlx4_en_deactivate_cq(priv, cq); 17398c2ecf20Sopenharmony_ci goto tx_err; 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci clear_bit(MLX4_EN_TX_RING_STATE_RECOVERING, &tx_ring->state); 17428c2ecf20Sopenharmony_ci if (t != TX_XDP) { 17438c2ecf20Sopenharmony_ci tx_ring->tx_queue = netdev_get_tx_queue(dev, i); 17448c2ecf20Sopenharmony_ci tx_ring->recycle_ring = NULL; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci /* Arm CQ for TX completions */ 17478c2ecf20Sopenharmony_ci mlx4_en_arm_cq(priv, cq); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci } else { 17508c2ecf20Sopenharmony_ci mlx4_en_init_tx_xdp_ring_descs(priv, tx_ring); 17518c2ecf20Sopenharmony_ci mlx4_en_init_recycle_ring(priv, i); 17528c2ecf20Sopenharmony_ci /* XDP TX CQ should never be armed */ 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci /* Set initial ownership of all Tx TXBBs to SW (1) */ 17568c2ecf20Sopenharmony_ci for (j = 0; j < tx_ring->buf_size; j += STAMP_STRIDE) 17578c2ecf20Sopenharmony_ci *((u32 *)(tx_ring->buf + j)) = 0xffffffff; 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* Configure port */ 17628c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_general(mdev->dev, priv->port, 17638c2ecf20Sopenharmony_ci priv->rx_skb_size + ETH_FCS_LEN, 17648c2ecf20Sopenharmony_ci priv->prof->tx_pause, 17658c2ecf20Sopenharmony_ci priv->prof->tx_ppp, 17668c2ecf20Sopenharmony_ci priv->prof->rx_pause, 17678c2ecf20Sopenharmony_ci priv->prof->rx_ppp); 17688c2ecf20Sopenharmony_ci if (err) { 17698c2ecf20Sopenharmony_ci en_err(priv, "Failed setting port general configurations for port %d, with error %d\n", 17708c2ecf20Sopenharmony_ci priv->port, err); 17718c2ecf20Sopenharmony_ci goto tx_err; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_user_mtu(mdev->dev, priv->port, dev->mtu); 17758c2ecf20Sopenharmony_ci if (err) { 17768c2ecf20Sopenharmony_ci en_err(priv, "Failed to pass user MTU(%d) to Firmware for port %d, with error %d\n", 17778c2ecf20Sopenharmony_ci dev->mtu, priv->port, err); 17788c2ecf20Sopenharmony_ci goto tx_err; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci /* Set default qp number */ 17828c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_qpn_calc(mdev->dev, priv->port, priv->base_qpn, 0); 17838c2ecf20Sopenharmony_ci if (err) { 17848c2ecf20Sopenharmony_ci en_err(priv, "Failed setting default qp numbers\n"); 17858c2ecf20Sopenharmony_ci goto tx_err; 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) { 17898c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC, 1); 17908c2ecf20Sopenharmony_ci if (err) { 17918c2ecf20Sopenharmony_ci en_err(priv, "Failed setting port L2 tunnel configuration, err %d\n", 17928c2ecf20Sopenharmony_ci err); 17938c2ecf20Sopenharmony_ci goto tx_err; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci /* Init port */ 17988c2ecf20Sopenharmony_ci en_dbg(HW, priv, "Initializing port\n"); 17998c2ecf20Sopenharmony_ci err = mlx4_INIT_PORT(mdev->dev, priv->port); 18008c2ecf20Sopenharmony_ci if (err) { 18018c2ecf20Sopenharmony_ci en_err(priv, "Failed Initializing port\n"); 18028c2ecf20Sopenharmony_ci goto tx_err; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci /* Set Unicast and VXLAN steering rules */ 18068c2ecf20Sopenharmony_ci if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0 && 18078c2ecf20Sopenharmony_ci mlx4_en_set_rss_steer_rules(priv)) 18088c2ecf20Sopenharmony_ci mlx4_warn(mdev, "Failed setting steering rules\n"); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci /* Attach rx QP to bradcast address */ 18118c2ecf20Sopenharmony_ci eth_broadcast_addr(&mc_list[10]); 18128c2ecf20Sopenharmony_ci mc_list[5] = priv->port; /* needed for B0 steering support */ 18138c2ecf20Sopenharmony_ci if (mlx4_multicast_attach(mdev->dev, priv->rss_map.indir_qp, mc_list, 18148c2ecf20Sopenharmony_ci priv->port, 0, MLX4_PROT_ETH, 18158c2ecf20Sopenharmony_ci &priv->broadcast_id)) 18168c2ecf20Sopenharmony_ci mlx4_warn(mdev, "Failed Attaching Broadcast\n"); 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci /* Must redo promiscuous mode setup. */ 18198c2ecf20Sopenharmony_ci priv->flags &= ~(MLX4_EN_FLAG_PROMISC | MLX4_EN_FLAG_MC_PROMISC); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* Schedule multicast task to populate multicast list */ 18228c2ecf20Sopenharmony_ci queue_work(mdev->workqueue, &priv->rx_mode_task); 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci if (priv->mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) 18258c2ecf20Sopenharmony_ci udp_tunnel_nic_reset_ntf(dev); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci priv->port_up = true; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci /* Process all completions if exist to prevent 18308c2ecf20Sopenharmony_ci * the queues freezing if they are full 18318c2ecf20Sopenharmony_ci */ 18328c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 18338c2ecf20Sopenharmony_ci local_bh_disable(); 18348c2ecf20Sopenharmony_ci napi_schedule(&priv->rx_cq[i]->napi); 18358c2ecf20Sopenharmony_ci local_bh_enable(); 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci clear_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state); 18398c2ecf20Sopenharmony_ci netif_tx_start_all_queues(dev); 18408c2ecf20Sopenharmony_ci netif_device_attach(dev); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci return 0; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_citx_err: 18458c2ecf20Sopenharmony_ci if (t == MLX4_EN_NUM_TX_TYPES) { 18468c2ecf20Sopenharmony_ci t--; 18478c2ecf20Sopenharmony_ci i = priv->tx_ring_num[t]; 18488c2ecf20Sopenharmony_ci } 18498c2ecf20Sopenharmony_ci while (t >= 0) { 18508c2ecf20Sopenharmony_ci while (i--) { 18518c2ecf20Sopenharmony_ci mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[t][i]); 18528c2ecf20Sopenharmony_ci mlx4_en_deactivate_cq(priv, priv->tx_cq[t][i]); 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci if (!t--) 18558c2ecf20Sopenharmony_ci break; 18568c2ecf20Sopenharmony_ci i = priv->tx_ring_num[t]; 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci mlx4_en_destroy_drop_qp(priv); 18598c2ecf20Sopenharmony_cirss_err: 18608c2ecf20Sopenharmony_ci mlx4_en_release_rss_steer(priv); 18618c2ecf20Sopenharmony_cimac_err: 18628c2ecf20Sopenharmony_ci mlx4_en_put_qp(priv); 18638c2ecf20Sopenharmony_cicq_err: 18648c2ecf20Sopenharmony_ci while (rx_index--) { 18658c2ecf20Sopenharmony_ci mlx4_en_deactivate_cq(priv, priv->rx_cq[rx_index]); 18668c2ecf20Sopenharmony_ci mlx4_en_free_affinity_hint(priv, rx_index); 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) 18698c2ecf20Sopenharmony_ci mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci return err; /* need to close devices */ 18728c2ecf20Sopenharmony_ci} 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_civoid mlx4_en_stop_port(struct net_device *dev, int detach) 18768c2ecf20Sopenharmony_ci{ 18778c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 18788c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 18798c2ecf20Sopenharmony_ci struct mlx4_en_mc_list *mclist, *tmp; 18808c2ecf20Sopenharmony_ci struct ethtool_flow_id *flow, *tmp_flow; 18818c2ecf20Sopenharmony_ci int i, t; 18828c2ecf20Sopenharmony_ci u8 mc_list[16] = {0}; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci if (!priv->port_up) { 18858c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "stop port called while port already down\n"); 18868c2ecf20Sopenharmony_ci return; 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci /* close port*/ 18908c2ecf20Sopenharmony_ci mlx4_CLOSE_PORT(mdev->dev, priv->port); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci /* Synchronize with tx routine */ 18938c2ecf20Sopenharmony_ci netif_tx_lock_bh(dev); 18948c2ecf20Sopenharmony_ci if (detach) 18958c2ecf20Sopenharmony_ci netif_device_detach(dev); 18968c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(dev); 18978c2ecf20Sopenharmony_ci netif_tx_unlock_bh(dev); 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci netif_tx_disable(dev); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci spin_lock_bh(&priv->stats_lock); 19028c2ecf20Sopenharmony_ci mlx4_en_fold_software_stats(dev); 19038c2ecf20Sopenharmony_ci /* Set port as not active */ 19048c2ecf20Sopenharmony_ci priv->port_up = false; 19058c2ecf20Sopenharmony_ci spin_unlock_bh(&priv->stats_lock); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci priv->counter_index = MLX4_SINK_COUNTER_INDEX(mdev->dev); 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci /* Promsicuous mode */ 19108c2ecf20Sopenharmony_ci if (mdev->dev->caps.steering_mode == 19118c2ecf20Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED) { 19128c2ecf20Sopenharmony_ci priv->flags &= ~(MLX4_EN_FLAG_PROMISC | 19138c2ecf20Sopenharmony_ci MLX4_EN_FLAG_MC_PROMISC); 19148c2ecf20Sopenharmony_ci mlx4_flow_steer_promisc_remove(mdev->dev, 19158c2ecf20Sopenharmony_ci priv->port, 19168c2ecf20Sopenharmony_ci MLX4_FS_ALL_DEFAULT); 19178c2ecf20Sopenharmony_ci mlx4_flow_steer_promisc_remove(mdev->dev, 19188c2ecf20Sopenharmony_ci priv->port, 19198c2ecf20Sopenharmony_ci MLX4_FS_MC_DEFAULT); 19208c2ecf20Sopenharmony_ci } else if (priv->flags & MLX4_EN_FLAG_PROMISC) { 19218c2ecf20Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_PROMISC; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci /* Disable promiscouos mode */ 19248c2ecf20Sopenharmony_ci mlx4_unicast_promisc_remove(mdev->dev, priv->base_qpn, 19258c2ecf20Sopenharmony_ci priv->port); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci /* Disable Multicast promisc */ 19288c2ecf20Sopenharmony_ci if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 19298c2ecf20Sopenharmony_ci mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, 19308c2ecf20Sopenharmony_ci priv->port); 19318c2ecf20Sopenharmony_ci priv->flags &= ~MLX4_EN_FLAG_MC_PROMISC; 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci } 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci /* Detach All multicasts */ 19368c2ecf20Sopenharmony_ci eth_broadcast_addr(&mc_list[10]); 19378c2ecf20Sopenharmony_ci mc_list[5] = priv->port; /* needed for B0 steering support */ 19388c2ecf20Sopenharmony_ci mlx4_multicast_detach(mdev->dev, priv->rss_map.indir_qp, mc_list, 19398c2ecf20Sopenharmony_ci MLX4_PROT_ETH, priv->broadcast_id); 19408c2ecf20Sopenharmony_ci list_for_each_entry(mclist, &priv->curr_list, list) { 19418c2ecf20Sopenharmony_ci memcpy(&mc_list[10], mclist->addr, ETH_ALEN); 19428c2ecf20Sopenharmony_ci mc_list[5] = priv->port; 19438c2ecf20Sopenharmony_ci mlx4_multicast_detach(mdev->dev, priv->rss_map.indir_qp, 19448c2ecf20Sopenharmony_ci mc_list, MLX4_PROT_ETH, mclist->reg_id); 19458c2ecf20Sopenharmony_ci if (mclist->tunnel_reg_id) 19468c2ecf20Sopenharmony_ci mlx4_flow_detach(mdev->dev, mclist->tunnel_reg_id); 19478c2ecf20Sopenharmony_ci } 19488c2ecf20Sopenharmony_ci mlx4_en_clear_list(dev); 19498c2ecf20Sopenharmony_ci list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) { 19508c2ecf20Sopenharmony_ci list_del(&mclist->list); 19518c2ecf20Sopenharmony_ci kfree(mclist); 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci /* Flush multicast filter */ 19558c2ecf20Sopenharmony_ci mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG); 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci /* Remove flow steering rules for the port*/ 19588c2ecf20Sopenharmony_ci if (mdev->dev->caps.steering_mode == 19598c2ecf20Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED) { 19608c2ecf20Sopenharmony_ci ASSERT_RTNL(); 19618c2ecf20Sopenharmony_ci list_for_each_entry_safe(flow, tmp_flow, 19628c2ecf20Sopenharmony_ci &priv->ethtool_list, list) { 19638c2ecf20Sopenharmony_ci mlx4_flow_detach(mdev->dev, flow->id); 19648c2ecf20Sopenharmony_ci list_del(&flow->list); 19658c2ecf20Sopenharmony_ci } 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci mlx4_en_destroy_drop_qp(priv); 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci /* Free TX Rings */ 19718c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 19728c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 19738c2ecf20Sopenharmony_ci mlx4_en_deactivate_tx_ring(priv, priv->tx_ring[t][i]); 19748c2ecf20Sopenharmony_ci mlx4_en_deactivate_cq(priv, priv->tx_cq[t][i]); 19758c2ecf20Sopenharmony_ci } 19768c2ecf20Sopenharmony_ci } 19778c2ecf20Sopenharmony_ci msleep(10); 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) 19808c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) 19818c2ecf20Sopenharmony_ci mlx4_en_free_tx_buf(dev, priv->tx_ring[t][i]); 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 19848c2ecf20Sopenharmony_ci mlx4_en_delete_rss_steer_rules(priv); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci /* Free RSS qps */ 19878c2ecf20Sopenharmony_ci mlx4_en_release_rss_steer(priv); 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci /* Unregister Mac address for the port */ 19908c2ecf20Sopenharmony_ci mlx4_en_put_qp(priv); 19918c2ecf20Sopenharmony_ci if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN)) 19928c2ecf20Sopenharmony_ci mdev->mac_removed[priv->port] = 1; 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci /* Free RX Rings */ 19958c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 19968c2ecf20Sopenharmony_ci struct mlx4_en_cq *cq = priv->rx_cq[i]; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci napi_synchronize(&cq->napi); 19998c2ecf20Sopenharmony_ci mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]); 20008c2ecf20Sopenharmony_ci mlx4_en_deactivate_cq(priv, cq); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci mlx4_en_free_affinity_hint(priv, i); 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci} 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_cistatic void mlx4_en_restart(struct work_struct *work) 20078c2ecf20Sopenharmony_ci{ 20088c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 20098c2ecf20Sopenharmony_ci restart_task); 20108c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 20118c2ecf20Sopenharmony_ci struct net_device *dev = priv->dev; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port); 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci rtnl_lock(); 20168c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 20178c2ecf20Sopenharmony_ci if (priv->port_up) { 20188c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 1); 20198c2ecf20Sopenharmony_ci if (mlx4_en_start_port(dev)) 20208c2ecf20Sopenharmony_ci en_err(priv, "Failed restarting port %d\n", priv->port); 20218c2ecf20Sopenharmony_ci } 20228c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 20238c2ecf20Sopenharmony_ci rtnl_unlock(); 20248c2ecf20Sopenharmony_ci} 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_cistatic void mlx4_en_clear_stats(struct net_device *dev) 20278c2ecf20Sopenharmony_ci{ 20288c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 20298c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 20308c2ecf20Sopenharmony_ci struct mlx4_en_tx_ring **tx_ring; 20318c2ecf20Sopenharmony_ci int i; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci if (!mlx4_is_slave(mdev->dev)) 20348c2ecf20Sopenharmony_ci if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1)) 20358c2ecf20Sopenharmony_ci en_dbg(HW, priv, "Failed dumping statistics\n"); 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci memset(&priv->pstats, 0, sizeof(priv->pstats)); 20388c2ecf20Sopenharmony_ci memset(&priv->pkstats, 0, sizeof(priv->pkstats)); 20398c2ecf20Sopenharmony_ci memset(&priv->port_stats, 0, sizeof(priv->port_stats)); 20408c2ecf20Sopenharmony_ci memset(&priv->rx_flowstats, 0, sizeof(priv->rx_flowstats)); 20418c2ecf20Sopenharmony_ci memset(&priv->tx_flowstats, 0, sizeof(priv->tx_flowstats)); 20428c2ecf20Sopenharmony_ci memset(&priv->rx_priority_flowstats, 0, 20438c2ecf20Sopenharmony_ci sizeof(priv->rx_priority_flowstats)); 20448c2ecf20Sopenharmony_ci memset(&priv->tx_priority_flowstats, 0, 20458c2ecf20Sopenharmony_ci sizeof(priv->tx_priority_flowstats)); 20468c2ecf20Sopenharmony_ci memset(&priv->pf_stats, 0, sizeof(priv->pf_stats)); 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci tx_ring = priv->tx_ring[TX]; 20498c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[TX]; i++) { 20508c2ecf20Sopenharmony_ci tx_ring[i]->bytes = 0; 20518c2ecf20Sopenharmony_ci tx_ring[i]->packets = 0; 20528c2ecf20Sopenharmony_ci tx_ring[i]->tx_csum = 0; 20538c2ecf20Sopenharmony_ci tx_ring[i]->tx_dropped = 0; 20548c2ecf20Sopenharmony_ci tx_ring[i]->queue_stopped = 0; 20558c2ecf20Sopenharmony_ci tx_ring[i]->wake_queue = 0; 20568c2ecf20Sopenharmony_ci tx_ring[i]->tso_packets = 0; 20578c2ecf20Sopenharmony_ci tx_ring[i]->xmit_more = 0; 20588c2ecf20Sopenharmony_ci } 20598c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 20608c2ecf20Sopenharmony_ci priv->rx_ring[i]->bytes = 0; 20618c2ecf20Sopenharmony_ci priv->rx_ring[i]->packets = 0; 20628c2ecf20Sopenharmony_ci priv->rx_ring[i]->csum_ok = 0; 20638c2ecf20Sopenharmony_ci priv->rx_ring[i]->csum_none = 0; 20648c2ecf20Sopenharmony_ci priv->rx_ring[i]->csum_complete = 0; 20658c2ecf20Sopenharmony_ci } 20668c2ecf20Sopenharmony_ci} 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_cistatic int mlx4_en_open(struct net_device *dev) 20698c2ecf20Sopenharmony_ci{ 20708c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 20718c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 20728c2ecf20Sopenharmony_ci int err = 0; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci if (!mdev->device_up) { 20778c2ecf20Sopenharmony_ci en_err(priv, "Cannot open - device down/disabled\n"); 20788c2ecf20Sopenharmony_ci err = -EBUSY; 20798c2ecf20Sopenharmony_ci goto out; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci /* Reset HW statistics and SW counters */ 20838c2ecf20Sopenharmony_ci mlx4_en_clear_stats(dev); 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci err = mlx4_en_start_port(dev); 20868c2ecf20Sopenharmony_ci if (err) 20878c2ecf20Sopenharmony_ci en_err(priv, "Failed starting port:%d\n", priv->port); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ciout: 20908c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 20918c2ecf20Sopenharmony_ci return err; 20928c2ecf20Sopenharmony_ci} 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic int mlx4_en_close(struct net_device *dev) 20968c2ecf20Sopenharmony_ci{ 20978c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 20988c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci en_dbg(IFDOWN, priv, "Close port called\n"); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 0); 21058c2ecf20Sopenharmony_ci netif_carrier_off(dev); 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 21088c2ecf20Sopenharmony_ci return 0; 21098c2ecf20Sopenharmony_ci} 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_cistatic void mlx4_en_free_resources(struct mlx4_en_priv *priv) 21128c2ecf20Sopenharmony_ci{ 21138c2ecf20Sopenharmony_ci int i, t; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 21168c2ecf20Sopenharmony_ci priv->dev->rx_cpu_rmap = NULL; 21178c2ecf20Sopenharmony_ci#endif 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 21208c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 21218c2ecf20Sopenharmony_ci if (priv->tx_ring[t] && priv->tx_ring[t][i]) 21228c2ecf20Sopenharmony_ci mlx4_en_destroy_tx_ring(priv, 21238c2ecf20Sopenharmony_ci &priv->tx_ring[t][i]); 21248c2ecf20Sopenharmony_ci if (priv->tx_cq[t] && priv->tx_cq[t][i]) 21258c2ecf20Sopenharmony_ci mlx4_en_destroy_cq(priv, &priv->tx_cq[t][i]); 21268c2ecf20Sopenharmony_ci } 21278c2ecf20Sopenharmony_ci kfree(priv->tx_ring[t]); 21288c2ecf20Sopenharmony_ci kfree(priv->tx_cq[t]); 21298c2ecf20Sopenharmony_ci } 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 21328c2ecf20Sopenharmony_ci if (priv->rx_ring[i]) 21338c2ecf20Sopenharmony_ci mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], 21348c2ecf20Sopenharmony_ci priv->prof->rx_ring_size, priv->stride); 21358c2ecf20Sopenharmony_ci if (priv->rx_cq[i]) 21368c2ecf20Sopenharmony_ci mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci} 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_cistatic int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) 21428c2ecf20Sopenharmony_ci{ 21438c2ecf20Sopenharmony_ci struct mlx4_en_port_profile *prof = priv->prof; 21448c2ecf20Sopenharmony_ci int i, t; 21458c2ecf20Sopenharmony_ci int node; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci /* Create tx Rings */ 21488c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 21498c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 21508c2ecf20Sopenharmony_ci node = cpu_to_node(i % num_online_cpus()); 21518c2ecf20Sopenharmony_ci if (mlx4_en_create_cq(priv, &priv->tx_cq[t][i], 21528c2ecf20Sopenharmony_ci prof->tx_ring_size, i, t, node)) 21538c2ecf20Sopenharmony_ci goto err; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci if (mlx4_en_create_tx_ring(priv, &priv->tx_ring[t][i], 21568c2ecf20Sopenharmony_ci prof->tx_ring_size, 21578c2ecf20Sopenharmony_ci TXBB_SIZE, node, i)) 21588c2ecf20Sopenharmony_ci goto err; 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci /* Create rx Rings */ 21638c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 21648c2ecf20Sopenharmony_ci node = cpu_to_node(i % num_online_cpus()); 21658c2ecf20Sopenharmony_ci if (mlx4_en_create_cq(priv, &priv->rx_cq[i], 21668c2ecf20Sopenharmony_ci prof->rx_ring_size, i, RX, node)) 21678c2ecf20Sopenharmony_ci goto err; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci if (mlx4_en_create_rx_ring(priv, &priv->rx_ring[i], 21708c2ecf20Sopenharmony_ci prof->rx_ring_size, priv->stride, 21718c2ecf20Sopenharmony_ci node, i)) 21728c2ecf20Sopenharmony_ci goto err; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 21778c2ecf20Sopenharmony_ci priv->dev->rx_cpu_rmap = mlx4_get_cpu_rmap(priv->mdev->dev, priv->port); 21788c2ecf20Sopenharmony_ci#endif 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci return 0; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_cierr: 21838c2ecf20Sopenharmony_ci en_err(priv, "Failed to allocate NIC resources\n"); 21848c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 21858c2ecf20Sopenharmony_ci if (priv->rx_ring[i]) 21868c2ecf20Sopenharmony_ci mlx4_en_destroy_rx_ring(priv, &priv->rx_ring[i], 21878c2ecf20Sopenharmony_ci prof->rx_ring_size, 21888c2ecf20Sopenharmony_ci priv->stride); 21898c2ecf20Sopenharmony_ci if (priv->rx_cq[i]) 21908c2ecf20Sopenharmony_ci mlx4_en_destroy_cq(priv, &priv->rx_cq[i]); 21918c2ecf20Sopenharmony_ci } 21928c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 21938c2ecf20Sopenharmony_ci for (i = 0; i < priv->tx_ring_num[t]; i++) { 21948c2ecf20Sopenharmony_ci if (priv->tx_ring[t][i]) 21958c2ecf20Sopenharmony_ci mlx4_en_destroy_tx_ring(priv, 21968c2ecf20Sopenharmony_ci &priv->tx_ring[t][i]); 21978c2ecf20Sopenharmony_ci if (priv->tx_cq[t][i]) 21988c2ecf20Sopenharmony_ci mlx4_en_destroy_cq(priv, &priv->tx_cq[t][i]); 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci return -ENOMEM; 22028c2ecf20Sopenharmony_ci} 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cistatic int mlx4_en_copy_priv(struct mlx4_en_priv *dst, 22068c2ecf20Sopenharmony_ci struct mlx4_en_priv *src, 22078c2ecf20Sopenharmony_ci struct mlx4_en_port_profile *prof) 22088c2ecf20Sopenharmony_ci{ 22098c2ecf20Sopenharmony_ci int t; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci memcpy(&dst->hwtstamp_config, &prof->hwtstamp_config, 22128c2ecf20Sopenharmony_ci sizeof(dst->hwtstamp_config)); 22138c2ecf20Sopenharmony_ci dst->num_tx_rings_p_up = prof->num_tx_rings_p_up; 22148c2ecf20Sopenharmony_ci dst->rx_ring_num = prof->rx_ring_num; 22158c2ecf20Sopenharmony_ci dst->flags = prof->flags; 22168c2ecf20Sopenharmony_ci dst->mdev = src->mdev; 22178c2ecf20Sopenharmony_ci dst->port = src->port; 22188c2ecf20Sopenharmony_ci dst->dev = src->dev; 22198c2ecf20Sopenharmony_ci dst->prof = prof; 22208c2ecf20Sopenharmony_ci dst->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + 22218c2ecf20Sopenharmony_ci DS_SIZE * MLX4_EN_MAX_RX_FRAGS); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 22248c2ecf20Sopenharmony_ci dst->tx_ring_num[t] = prof->tx_ring_num[t]; 22258c2ecf20Sopenharmony_ci if (!dst->tx_ring_num[t]) 22268c2ecf20Sopenharmony_ci continue; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci dst->tx_ring[t] = kcalloc(MAX_TX_RINGS, 22298c2ecf20Sopenharmony_ci sizeof(struct mlx4_en_tx_ring *), 22308c2ecf20Sopenharmony_ci GFP_KERNEL); 22318c2ecf20Sopenharmony_ci if (!dst->tx_ring[t]) 22328c2ecf20Sopenharmony_ci goto err_free_tx; 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci dst->tx_cq[t] = kcalloc(MAX_TX_RINGS, 22358c2ecf20Sopenharmony_ci sizeof(struct mlx4_en_cq *), 22368c2ecf20Sopenharmony_ci GFP_KERNEL); 22378c2ecf20Sopenharmony_ci if (!dst->tx_cq[t]) { 22388c2ecf20Sopenharmony_ci kfree(dst->tx_ring[t]); 22398c2ecf20Sopenharmony_ci goto err_free_tx; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci return 0; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_cierr_free_tx: 22468c2ecf20Sopenharmony_ci while (t--) { 22478c2ecf20Sopenharmony_ci kfree(dst->tx_ring[t]); 22488c2ecf20Sopenharmony_ci kfree(dst->tx_cq[t]); 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci return -ENOMEM; 22518c2ecf20Sopenharmony_ci} 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_cistatic void mlx4_en_update_priv(struct mlx4_en_priv *dst, 22548c2ecf20Sopenharmony_ci struct mlx4_en_priv *src) 22558c2ecf20Sopenharmony_ci{ 22568c2ecf20Sopenharmony_ci int t; 22578c2ecf20Sopenharmony_ci memcpy(dst->rx_ring, src->rx_ring, 22588c2ecf20Sopenharmony_ci sizeof(struct mlx4_en_rx_ring *) * src->rx_ring_num); 22598c2ecf20Sopenharmony_ci memcpy(dst->rx_cq, src->rx_cq, 22608c2ecf20Sopenharmony_ci sizeof(struct mlx4_en_cq *) * src->rx_ring_num); 22618c2ecf20Sopenharmony_ci memcpy(&dst->hwtstamp_config, &src->hwtstamp_config, 22628c2ecf20Sopenharmony_ci sizeof(dst->hwtstamp_config)); 22638c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 22648c2ecf20Sopenharmony_ci dst->tx_ring_num[t] = src->tx_ring_num[t]; 22658c2ecf20Sopenharmony_ci dst->tx_ring[t] = src->tx_ring[t]; 22668c2ecf20Sopenharmony_ci dst->tx_cq[t] = src->tx_cq[t]; 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci dst->num_tx_rings_p_up = src->num_tx_rings_p_up; 22698c2ecf20Sopenharmony_ci dst->rx_ring_num = src->rx_ring_num; 22708c2ecf20Sopenharmony_ci memcpy(dst->prof, src->prof, sizeof(struct mlx4_en_port_profile)); 22718c2ecf20Sopenharmony_ci} 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ciint mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv, 22748c2ecf20Sopenharmony_ci struct mlx4_en_priv *tmp, 22758c2ecf20Sopenharmony_ci struct mlx4_en_port_profile *prof, 22768c2ecf20Sopenharmony_ci bool carry_xdp_prog) 22778c2ecf20Sopenharmony_ci{ 22788c2ecf20Sopenharmony_ci struct bpf_prog *xdp_prog; 22798c2ecf20Sopenharmony_ci int i, t, ret; 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_ci ret = mlx4_en_copy_priv(tmp, priv, prof); 22828c2ecf20Sopenharmony_ci if (ret) { 22838c2ecf20Sopenharmony_ci en_warn(priv, "%s: mlx4_en_copy_priv() failed, return\n", 22848c2ecf20Sopenharmony_ci __func__); 22858c2ecf20Sopenharmony_ci return ret; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci if (mlx4_en_alloc_resources(tmp)) { 22898c2ecf20Sopenharmony_ci en_warn(priv, 22908c2ecf20Sopenharmony_ci "%s: Resource allocation failed, using previous configuration\n", 22918c2ecf20Sopenharmony_ci __func__); 22928c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 22938c2ecf20Sopenharmony_ci kfree(tmp->tx_ring[t]); 22948c2ecf20Sopenharmony_ci kfree(tmp->tx_cq[t]); 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci return -ENOMEM; 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci /* All rx_rings has the same xdp_prog. Pick the first one. */ 23008c2ecf20Sopenharmony_ci xdp_prog = rcu_dereference_protected( 23018c2ecf20Sopenharmony_ci priv->rx_ring[0]->xdp_prog, 23028c2ecf20Sopenharmony_ci lockdep_is_held(&priv->mdev->state_lock)); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci if (xdp_prog && carry_xdp_prog) { 23058c2ecf20Sopenharmony_ci bpf_prog_add(xdp_prog, tmp->rx_ring_num); 23068c2ecf20Sopenharmony_ci for (i = 0; i < tmp->rx_ring_num; i++) 23078c2ecf20Sopenharmony_ci rcu_assign_pointer(tmp->rx_ring[i]->xdp_prog, 23088c2ecf20Sopenharmony_ci xdp_prog); 23098c2ecf20Sopenharmony_ci } 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci return 0; 23128c2ecf20Sopenharmony_ci} 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_civoid mlx4_en_safe_replace_resources(struct mlx4_en_priv *priv, 23158c2ecf20Sopenharmony_ci struct mlx4_en_priv *tmp) 23168c2ecf20Sopenharmony_ci{ 23178c2ecf20Sopenharmony_ci mlx4_en_free_resources(priv); 23188c2ecf20Sopenharmony_ci mlx4_en_update_priv(priv, tmp); 23198c2ecf20Sopenharmony_ci} 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_civoid mlx4_en_destroy_netdev(struct net_device *dev) 23228c2ecf20Sopenharmony_ci{ 23238c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 23248c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci /* Unregister device - this will close the port if it was up */ 23298c2ecf20Sopenharmony_ci if (priv->registered) { 23308c2ecf20Sopenharmony_ci devlink_port_type_clear(mlx4_get_devlink_port(mdev->dev, 23318c2ecf20Sopenharmony_ci priv->port)); 23328c2ecf20Sopenharmony_ci unregister_netdev(dev); 23338c2ecf20Sopenharmony_ci } 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci if (priv->allocated) 23368c2ecf20Sopenharmony_ci mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE); 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci cancel_delayed_work(&priv->stats_task); 23398c2ecf20Sopenharmony_ci cancel_delayed_work(&priv->service_task); 23408c2ecf20Sopenharmony_ci /* flush any pending task for this netdev */ 23418c2ecf20Sopenharmony_ci flush_workqueue(mdev->workqueue); 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) 23448c2ecf20Sopenharmony_ci mlx4_en_remove_timestamp(mdev); 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci /* Detach the netdev so tasks would not attempt to access it */ 23478c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 23488c2ecf20Sopenharmony_ci mdev->pndev[priv->port] = NULL; 23498c2ecf20Sopenharmony_ci mdev->upper[priv->port] = NULL; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 23528c2ecf20Sopenharmony_ci mlx4_en_cleanup_filters(priv); 23538c2ecf20Sopenharmony_ci#endif 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci mlx4_en_free_resources(priv); 23568c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci free_netdev(dev); 23598c2ecf20Sopenharmony_ci} 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_cistatic bool mlx4_en_check_xdp_mtu(struct net_device *dev, int mtu) 23628c2ecf20Sopenharmony_ci{ 23638c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci if (mtu > MLX4_EN_MAX_XDP_MTU) { 23668c2ecf20Sopenharmony_ci en_err(priv, "mtu:%d > max:%d when XDP prog is attached\n", 23678c2ecf20Sopenharmony_ci mtu, MLX4_EN_MAX_XDP_MTU); 23688c2ecf20Sopenharmony_ci return false; 23698c2ecf20Sopenharmony_ci } 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci return true; 23728c2ecf20Sopenharmony_ci} 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_cistatic int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) 23758c2ecf20Sopenharmony_ci{ 23768c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 23778c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 23788c2ecf20Sopenharmony_ci int err = 0; 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Change MTU called - current:%d new:%d\n", 23818c2ecf20Sopenharmony_ci dev->mtu, new_mtu); 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci if (priv->tx_ring_num[TX_XDP] && 23848c2ecf20Sopenharmony_ci !mlx4_en_check_xdp_mtu(dev, new_mtu)) 23858c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci if (netif_running(dev)) { 23908c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 23918c2ecf20Sopenharmony_ci if (!mdev->device_up) { 23928c2ecf20Sopenharmony_ci /* NIC is probably restarting - let restart task reset 23938c2ecf20Sopenharmony_ci * the port */ 23948c2ecf20Sopenharmony_ci en_dbg(DRV, priv, "Change MTU called with card down!?\n"); 23958c2ecf20Sopenharmony_ci } else { 23968c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 1); 23978c2ecf20Sopenharmony_ci err = mlx4_en_start_port(dev); 23988c2ecf20Sopenharmony_ci if (err) { 23998c2ecf20Sopenharmony_ci en_err(priv, "Failed restarting port:%d\n", 24008c2ecf20Sopenharmony_ci priv->port); 24018c2ecf20Sopenharmony_ci if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, 24028c2ecf20Sopenharmony_ci &priv->state)) 24038c2ecf20Sopenharmony_ci queue_work(mdev->workqueue, &priv->restart_task); 24048c2ecf20Sopenharmony_ci } 24058c2ecf20Sopenharmony_ci } 24068c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci return 0; 24098c2ecf20Sopenharmony_ci} 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_cistatic int mlx4_en_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 24148c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 24158c2ecf20Sopenharmony_ci struct hwtstamp_config config; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 24188c2ecf20Sopenharmony_ci return -EFAULT; 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci /* reserved for future extensions */ 24218c2ecf20Sopenharmony_ci if (config.flags) 24228c2ecf20Sopenharmony_ci return -EINVAL; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci /* device doesn't support time stamping */ 24258c2ecf20Sopenharmony_ci if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)) 24268c2ecf20Sopenharmony_ci return -EINVAL; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci /* TX HW timestamp */ 24298c2ecf20Sopenharmony_ci switch (config.tx_type) { 24308c2ecf20Sopenharmony_ci case HWTSTAMP_TX_OFF: 24318c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ON: 24328c2ecf20Sopenharmony_ci break; 24338c2ecf20Sopenharmony_ci default: 24348c2ecf20Sopenharmony_ci return -ERANGE; 24358c2ecf20Sopenharmony_ci } 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci /* RX HW timestamp */ 24388c2ecf20Sopenharmony_ci switch (config.rx_filter) { 24398c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 24408c2ecf20Sopenharmony_ci break; 24418c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 24428c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_SOME: 24438c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 24448c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 24458c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 24468c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 24478c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 24488c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 24498c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 24508c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 24518c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 24528c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 24538c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_SYNC: 24548c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 24558c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NTP_ALL: 24568c2ecf20Sopenharmony_ci config.rx_filter = HWTSTAMP_FILTER_ALL; 24578c2ecf20Sopenharmony_ci break; 24588c2ecf20Sopenharmony_ci default: 24598c2ecf20Sopenharmony_ci return -ERANGE; 24608c2ecf20Sopenharmony_ci } 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci if (mlx4_en_reset_config(dev, config, dev->features)) { 24638c2ecf20Sopenharmony_ci config.tx_type = HWTSTAMP_TX_OFF; 24648c2ecf20Sopenharmony_ci config.rx_filter = HWTSTAMP_FILTER_NONE; 24658c2ecf20Sopenharmony_ci } 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci return copy_to_user(ifr->ifr_data, &config, 24688c2ecf20Sopenharmony_ci sizeof(config)) ? -EFAULT : 0; 24698c2ecf20Sopenharmony_ci} 24708c2ecf20Sopenharmony_ci 24718c2ecf20Sopenharmony_cistatic int mlx4_en_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) 24728c2ecf20Sopenharmony_ci{ 24738c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci return copy_to_user(ifr->ifr_data, &priv->hwtstamp_config, 24768c2ecf20Sopenharmony_ci sizeof(priv->hwtstamp_config)) ? -EFAULT : 0; 24778c2ecf20Sopenharmony_ci} 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_cistatic int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 24808c2ecf20Sopenharmony_ci{ 24818c2ecf20Sopenharmony_ci switch (cmd) { 24828c2ecf20Sopenharmony_ci case SIOCSHWTSTAMP: 24838c2ecf20Sopenharmony_ci return mlx4_en_hwtstamp_set(dev, ifr); 24848c2ecf20Sopenharmony_ci case SIOCGHWTSTAMP: 24858c2ecf20Sopenharmony_ci return mlx4_en_hwtstamp_get(dev, ifr); 24868c2ecf20Sopenharmony_ci default: 24878c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci} 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_cistatic netdev_features_t mlx4_en_fix_features(struct net_device *netdev, 24928c2ecf20Sopenharmony_ci netdev_features_t features) 24938c2ecf20Sopenharmony_ci{ 24948c2ecf20Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(netdev); 24958c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci /* Since there is no support for separate RX C-TAG/S-TAG vlan accel 24988c2ecf20Sopenharmony_ci * enable/disable make sure S-TAG flag is always in same state as 24998c2ecf20Sopenharmony_ci * C-TAG. 25008c2ecf20Sopenharmony_ci */ 25018c2ecf20Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX && 25028c2ecf20Sopenharmony_ci !(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) 25038c2ecf20Sopenharmony_ci features |= NETIF_F_HW_VLAN_STAG_RX; 25048c2ecf20Sopenharmony_ci else 25058c2ecf20Sopenharmony_ci features &= ~NETIF_F_HW_VLAN_STAG_RX; 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci return features; 25088c2ecf20Sopenharmony_ci} 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_cistatic int mlx4_en_set_features(struct net_device *netdev, 25118c2ecf20Sopenharmony_ci netdev_features_t features) 25128c2ecf20Sopenharmony_ci{ 25138c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(netdev); 25148c2ecf20Sopenharmony_ci bool reset = false; 25158c2ecf20Sopenharmony_ci int ret = 0; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_RXFCS)) { 25188c2ecf20Sopenharmony_ci en_info(priv, "Turn %s RX-FCS\n", 25198c2ecf20Sopenharmony_ci (features & NETIF_F_RXFCS) ? "ON" : "OFF"); 25208c2ecf20Sopenharmony_ci reset = true; 25218c2ecf20Sopenharmony_ci } 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_RXALL)) { 25248c2ecf20Sopenharmony_ci u8 ignore_fcs_value = (features & NETIF_F_RXALL) ? 1 : 0; 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci en_info(priv, "Turn %s RX-ALL\n", 25278c2ecf20Sopenharmony_ci ignore_fcs_value ? "ON" : "OFF"); 25288c2ecf20Sopenharmony_ci ret = mlx4_SET_PORT_fcs_check(priv->mdev->dev, 25298c2ecf20Sopenharmony_ci priv->port, ignore_fcs_value); 25308c2ecf20Sopenharmony_ci if (ret) 25318c2ecf20Sopenharmony_ci return ret; 25328c2ecf20Sopenharmony_ci } 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_RX)) { 25358c2ecf20Sopenharmony_ci en_info(priv, "Turn %s RX vlan strip offload\n", 25368c2ecf20Sopenharmony_ci (features & NETIF_F_HW_VLAN_CTAG_RX) ? "ON" : "OFF"); 25378c2ecf20Sopenharmony_ci reset = true; 25388c2ecf20Sopenharmony_ci } 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_TX)) 25418c2ecf20Sopenharmony_ci en_info(priv, "Turn %s TX vlan strip offload\n", 25428c2ecf20Sopenharmony_ci (features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF"); 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_STAG_TX)) 25458c2ecf20Sopenharmony_ci en_info(priv, "Turn %s TX S-VLAN strip offload\n", 25468c2ecf20Sopenharmony_ci (features & NETIF_F_HW_VLAN_STAG_TX) ? "ON" : "OFF"); 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_LOOPBACK)) { 25498c2ecf20Sopenharmony_ci en_info(priv, "Turn %s loopback\n", 25508c2ecf20Sopenharmony_ci (features & NETIF_F_LOOPBACK) ? "ON" : "OFF"); 25518c2ecf20Sopenharmony_ci mlx4_en_update_loopback_state(netdev, features); 25528c2ecf20Sopenharmony_ci } 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci if (reset) { 25558c2ecf20Sopenharmony_ci ret = mlx4_en_reset_config(netdev, priv->hwtstamp_config, 25568c2ecf20Sopenharmony_ci features); 25578c2ecf20Sopenharmony_ci if (ret) 25588c2ecf20Sopenharmony_ci return ret; 25598c2ecf20Sopenharmony_ci } 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci return 0; 25628c2ecf20Sopenharmony_ci} 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_cistatic int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac) 25658c2ecf20Sopenharmony_ci{ 25668c2ecf20Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 25678c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac); 25708c2ecf20Sopenharmony_ci} 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_cistatic int mlx4_en_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos, 25738c2ecf20Sopenharmony_ci __be16 vlan_proto) 25748c2ecf20Sopenharmony_ci{ 25758c2ecf20Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 25768c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci return mlx4_set_vf_vlan(mdev->dev, en_priv->port, vf, vlan, qos, 25798c2ecf20Sopenharmony_ci vlan_proto); 25808c2ecf20Sopenharmony_ci} 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_cistatic int mlx4_en_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate, 25838c2ecf20Sopenharmony_ci int max_tx_rate) 25848c2ecf20Sopenharmony_ci{ 25858c2ecf20Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 25868c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci return mlx4_set_vf_rate(mdev->dev, en_priv->port, vf, min_tx_rate, 25898c2ecf20Sopenharmony_ci max_tx_rate); 25908c2ecf20Sopenharmony_ci} 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_cistatic int mlx4_en_set_vf_spoofchk(struct net_device *dev, int vf, bool setting) 25938c2ecf20Sopenharmony_ci{ 25948c2ecf20Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 25958c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci return mlx4_set_vf_spoofchk(mdev->dev, en_priv->port, vf, setting); 25988c2ecf20Sopenharmony_ci} 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_cistatic int mlx4_en_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivf) 26018c2ecf20Sopenharmony_ci{ 26028c2ecf20Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 26038c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci return mlx4_get_vf_config(mdev->dev, en_priv->port, vf, ivf); 26068c2ecf20Sopenharmony_ci} 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_cistatic int mlx4_en_set_vf_link_state(struct net_device *dev, int vf, int link_state) 26098c2ecf20Sopenharmony_ci{ 26108c2ecf20Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 26118c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci return mlx4_set_vf_link_state(mdev->dev, en_priv->port, vf, link_state); 26148c2ecf20Sopenharmony_ci} 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_cistatic int mlx4_en_get_vf_stats(struct net_device *dev, int vf, 26178c2ecf20Sopenharmony_ci struct ifla_vf_stats *vf_stats) 26188c2ecf20Sopenharmony_ci{ 26198c2ecf20Sopenharmony_ci struct mlx4_en_priv *en_priv = netdev_priv(dev); 26208c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = en_priv->mdev; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci return mlx4_get_vf_stats(mdev->dev, en_priv->port, vf, vf_stats); 26238c2ecf20Sopenharmony_ci} 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci#define PORT_ID_BYTE_LEN 8 26268c2ecf20Sopenharmony_cistatic int mlx4_en_get_phys_port_id(struct net_device *dev, 26278c2ecf20Sopenharmony_ci struct netdev_phys_item_id *ppid) 26288c2ecf20Sopenharmony_ci{ 26298c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 26308c2ecf20Sopenharmony_ci struct mlx4_dev *mdev = priv->mdev->dev; 26318c2ecf20Sopenharmony_ci int i; 26328c2ecf20Sopenharmony_ci u64 phys_port_id = mdev->caps.phys_port_id[priv->port]; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci if (!phys_port_id) 26358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci ppid->id_len = sizeof(phys_port_id); 26388c2ecf20Sopenharmony_ci for (i = PORT_ID_BYTE_LEN - 1; i >= 0; --i) { 26398c2ecf20Sopenharmony_ci ppid->id[i] = phys_port_id & 0xff; 26408c2ecf20Sopenharmony_ci phys_port_id >>= 8; 26418c2ecf20Sopenharmony_ci } 26428c2ecf20Sopenharmony_ci return 0; 26438c2ecf20Sopenharmony_ci} 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_cistatic int mlx4_udp_tunnel_sync(struct net_device *dev, unsigned int table) 26468c2ecf20Sopenharmony_ci{ 26478c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 26488c2ecf20Sopenharmony_ci struct udp_tunnel_info ti; 26498c2ecf20Sopenharmony_ci int ret; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci udp_tunnel_nic_get_port(dev, table, 0, &ti); 26528c2ecf20Sopenharmony_ci priv->vxlan_port = ti.port; 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci ret = mlx4_config_vxlan_port(priv->mdev->dev, priv->vxlan_port); 26558c2ecf20Sopenharmony_ci if (ret) 26568c2ecf20Sopenharmony_ci return ret; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci return mlx4_SET_PORT_VXLAN(priv->mdev->dev, priv->port, 26598c2ecf20Sopenharmony_ci VXLAN_STEER_BY_OUTER_MAC, 26608c2ecf20Sopenharmony_ci !!priv->vxlan_port); 26618c2ecf20Sopenharmony_ci} 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_cistatic const struct udp_tunnel_nic_info mlx4_udp_tunnels = { 26648c2ecf20Sopenharmony_ci .sync_table = mlx4_udp_tunnel_sync, 26658c2ecf20Sopenharmony_ci .flags = UDP_TUNNEL_NIC_INFO_MAY_SLEEP | 26668c2ecf20Sopenharmony_ci UDP_TUNNEL_NIC_INFO_IPV4_ONLY, 26678c2ecf20Sopenharmony_ci .tables = { 26688c2ecf20Sopenharmony_ci { .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, }, 26698c2ecf20Sopenharmony_ci }, 26708c2ecf20Sopenharmony_ci}; 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_cistatic netdev_features_t mlx4_en_features_check(struct sk_buff *skb, 26738c2ecf20Sopenharmony_ci struct net_device *dev, 26748c2ecf20Sopenharmony_ci netdev_features_t features) 26758c2ecf20Sopenharmony_ci{ 26768c2ecf20Sopenharmony_ci features = vlan_features_check(skb, features); 26778c2ecf20Sopenharmony_ci features = vxlan_features_check(skb, features); 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci /* The ConnectX-3 doesn't support outer IPv6 checksums but it does 26808c2ecf20Sopenharmony_ci * support inner IPv6 checksums and segmentation so we need to 26818c2ecf20Sopenharmony_ci * strip that feature if this is an IPv6 encapsulated frame. 26828c2ecf20Sopenharmony_ci */ 26838c2ecf20Sopenharmony_ci if (skb->encapsulation && 26848c2ecf20Sopenharmony_ci (skb->ip_summed == CHECKSUM_PARTIAL)) { 26858c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci if (!priv->vxlan_port || 26888c2ecf20Sopenharmony_ci (ip_hdr(skb)->version != 4) || 26898c2ecf20Sopenharmony_ci (udp_hdr(skb)->dest != priv->vxlan_port)) 26908c2ecf20Sopenharmony_ci features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); 26918c2ecf20Sopenharmony_ci } 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci return features; 26948c2ecf20Sopenharmony_ci} 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_cistatic int mlx4_en_set_tx_maxrate(struct net_device *dev, int queue_index, u32 maxrate) 26978c2ecf20Sopenharmony_ci{ 26988c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 26998c2ecf20Sopenharmony_ci struct mlx4_en_tx_ring *tx_ring = priv->tx_ring[TX][queue_index]; 27008c2ecf20Sopenharmony_ci struct mlx4_update_qp_params params; 27018c2ecf20Sopenharmony_ci int err; 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT)) 27048c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci /* rate provided to us in Mbs, check if it fits into 12 bits, if not use Gbs */ 27078c2ecf20Sopenharmony_ci if (maxrate >> 12) { 27088c2ecf20Sopenharmony_ci params.rate_unit = MLX4_QP_RATE_LIMIT_GBS; 27098c2ecf20Sopenharmony_ci params.rate_val = maxrate / 1000; 27108c2ecf20Sopenharmony_ci } else if (maxrate) { 27118c2ecf20Sopenharmony_ci params.rate_unit = MLX4_QP_RATE_LIMIT_MBS; 27128c2ecf20Sopenharmony_ci params.rate_val = maxrate; 27138c2ecf20Sopenharmony_ci } else { /* zero serves to revoke the QP rate-limitation */ 27148c2ecf20Sopenharmony_ci params.rate_unit = 0; 27158c2ecf20Sopenharmony_ci params.rate_val = 0; 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci err = mlx4_update_qp(priv->mdev->dev, tx_ring->qpn, MLX4_UPDATE_QP_RATE_LIMIT, 27198c2ecf20Sopenharmony_ci ¶ms); 27208c2ecf20Sopenharmony_ci return err; 27218c2ecf20Sopenharmony_ci} 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_cistatic int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) 27248c2ecf20Sopenharmony_ci{ 27258c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 27268c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 27278c2ecf20Sopenharmony_ci struct mlx4_en_port_profile new_prof; 27288c2ecf20Sopenharmony_ci struct bpf_prog *old_prog; 27298c2ecf20Sopenharmony_ci struct mlx4_en_priv *tmp; 27308c2ecf20Sopenharmony_ci int tx_changed = 0; 27318c2ecf20Sopenharmony_ci int xdp_ring_num; 27328c2ecf20Sopenharmony_ci int port_up = 0; 27338c2ecf20Sopenharmony_ci int err; 27348c2ecf20Sopenharmony_ci int i; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci xdp_ring_num = prog ? priv->rx_ring_num : 0; 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci /* No need to reconfigure buffers when simply swapping the 27398c2ecf20Sopenharmony_ci * program for a new one. 27408c2ecf20Sopenharmony_ci */ 27418c2ecf20Sopenharmony_ci if (priv->tx_ring_num[TX_XDP] == xdp_ring_num) { 27428c2ecf20Sopenharmony_ci if (prog) 27438c2ecf20Sopenharmony_ci bpf_prog_add(prog, priv->rx_ring_num - 1); 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 27468c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 27478c2ecf20Sopenharmony_ci old_prog = rcu_dereference_protected( 27488c2ecf20Sopenharmony_ci priv->rx_ring[i]->xdp_prog, 27498c2ecf20Sopenharmony_ci lockdep_is_held(&mdev->state_lock)); 27508c2ecf20Sopenharmony_ci rcu_assign_pointer(priv->rx_ring[i]->xdp_prog, prog); 27518c2ecf20Sopenharmony_ci if (old_prog) 27528c2ecf20Sopenharmony_ci bpf_prog_put(old_prog); 27538c2ecf20Sopenharmony_ci } 27548c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 27558c2ecf20Sopenharmony_ci return 0; 27568c2ecf20Sopenharmony_ci } 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci if (!mlx4_en_check_xdp_mtu(dev, dev->mtu)) 27598c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 27628c2ecf20Sopenharmony_ci if (!tmp) 27638c2ecf20Sopenharmony_ci return -ENOMEM; 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ci if (prog) 27668c2ecf20Sopenharmony_ci bpf_prog_add(prog, priv->rx_ring_num - 1); 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 27698c2ecf20Sopenharmony_ci memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); 27708c2ecf20Sopenharmony_ci new_prof.tx_ring_num[TX_XDP] = xdp_ring_num; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci if (priv->tx_ring_num[TX] + xdp_ring_num > MAX_TX_RINGS) { 27738c2ecf20Sopenharmony_ci tx_changed = 1; 27748c2ecf20Sopenharmony_ci new_prof.tx_ring_num[TX] = 27758c2ecf20Sopenharmony_ci MAX_TX_RINGS - ALIGN(xdp_ring_num, priv->prof->num_up); 27768c2ecf20Sopenharmony_ci en_warn(priv, "Reducing the number of TX rings, to not exceed the max total rings number.\n"); 27778c2ecf20Sopenharmony_ci } 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, false); 27808c2ecf20Sopenharmony_ci if (err) { 27818c2ecf20Sopenharmony_ci if (prog) 27828c2ecf20Sopenharmony_ci bpf_prog_sub(prog, priv->rx_ring_num - 1); 27838c2ecf20Sopenharmony_ci goto unlock_out; 27848c2ecf20Sopenharmony_ci } 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci if (priv->port_up) { 27878c2ecf20Sopenharmony_ci port_up = 1; 27888c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 1); 27898c2ecf20Sopenharmony_ci } 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci mlx4_en_safe_replace_resources(priv, tmp); 27928c2ecf20Sopenharmony_ci if (tx_changed) 27938c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(dev, priv->tx_ring_num[TX]); 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci for (i = 0; i < priv->rx_ring_num; i++) { 27968c2ecf20Sopenharmony_ci old_prog = rcu_dereference_protected( 27978c2ecf20Sopenharmony_ci priv->rx_ring[i]->xdp_prog, 27988c2ecf20Sopenharmony_ci lockdep_is_held(&mdev->state_lock)); 27998c2ecf20Sopenharmony_ci rcu_assign_pointer(priv->rx_ring[i]->xdp_prog, prog); 28008c2ecf20Sopenharmony_ci if (old_prog) 28018c2ecf20Sopenharmony_ci bpf_prog_put(old_prog); 28028c2ecf20Sopenharmony_ci } 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci if (port_up) { 28058c2ecf20Sopenharmony_ci err = mlx4_en_start_port(dev); 28068c2ecf20Sopenharmony_ci if (err) { 28078c2ecf20Sopenharmony_ci en_err(priv, "Failed starting port %d for XDP change\n", 28088c2ecf20Sopenharmony_ci priv->port); 28098c2ecf20Sopenharmony_ci if (!test_and_set_bit(MLX4_EN_STATE_FLAG_RESTARTING, &priv->state)) 28108c2ecf20Sopenharmony_ci queue_work(mdev->workqueue, &priv->restart_task); 28118c2ecf20Sopenharmony_ci } 28128c2ecf20Sopenharmony_ci } 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ciunlock_out: 28158c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 28168c2ecf20Sopenharmony_ci kfree(tmp); 28178c2ecf20Sopenharmony_ci return err; 28188c2ecf20Sopenharmony_ci} 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_cistatic int mlx4_xdp(struct net_device *dev, struct netdev_bpf *xdp) 28218c2ecf20Sopenharmony_ci{ 28228c2ecf20Sopenharmony_ci switch (xdp->command) { 28238c2ecf20Sopenharmony_ci case XDP_SETUP_PROG: 28248c2ecf20Sopenharmony_ci return mlx4_xdp_set(dev, xdp->prog); 28258c2ecf20Sopenharmony_ci default: 28268c2ecf20Sopenharmony_ci return -EINVAL; 28278c2ecf20Sopenharmony_ci } 28288c2ecf20Sopenharmony_ci} 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_cistatic const struct net_device_ops mlx4_netdev_ops = { 28318c2ecf20Sopenharmony_ci .ndo_open = mlx4_en_open, 28328c2ecf20Sopenharmony_ci .ndo_stop = mlx4_en_close, 28338c2ecf20Sopenharmony_ci .ndo_start_xmit = mlx4_en_xmit, 28348c2ecf20Sopenharmony_ci .ndo_select_queue = mlx4_en_select_queue, 28358c2ecf20Sopenharmony_ci .ndo_get_stats64 = mlx4_en_get_stats64, 28368c2ecf20Sopenharmony_ci .ndo_set_rx_mode = mlx4_en_set_rx_mode, 28378c2ecf20Sopenharmony_ci .ndo_set_mac_address = mlx4_en_set_mac, 28388c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 28398c2ecf20Sopenharmony_ci .ndo_change_mtu = mlx4_en_change_mtu, 28408c2ecf20Sopenharmony_ci .ndo_do_ioctl = mlx4_en_ioctl, 28418c2ecf20Sopenharmony_ci .ndo_tx_timeout = mlx4_en_tx_timeout, 28428c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid, 28438c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, 28448c2ecf20Sopenharmony_ci .ndo_set_features = mlx4_en_set_features, 28458c2ecf20Sopenharmony_ci .ndo_fix_features = mlx4_en_fix_features, 28468c2ecf20Sopenharmony_ci .ndo_setup_tc = __mlx4_en_setup_tc, 28478c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 28488c2ecf20Sopenharmony_ci .ndo_rx_flow_steer = mlx4_en_filter_rfs, 28498c2ecf20Sopenharmony_ci#endif 28508c2ecf20Sopenharmony_ci .ndo_get_phys_port_id = mlx4_en_get_phys_port_id, 28518c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 28528c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 28538c2ecf20Sopenharmony_ci .ndo_features_check = mlx4_en_features_check, 28548c2ecf20Sopenharmony_ci .ndo_set_tx_maxrate = mlx4_en_set_tx_maxrate, 28558c2ecf20Sopenharmony_ci .ndo_bpf = mlx4_xdp, 28568c2ecf20Sopenharmony_ci}; 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_cistatic const struct net_device_ops mlx4_netdev_ops_master = { 28598c2ecf20Sopenharmony_ci .ndo_open = mlx4_en_open, 28608c2ecf20Sopenharmony_ci .ndo_stop = mlx4_en_close, 28618c2ecf20Sopenharmony_ci .ndo_start_xmit = mlx4_en_xmit, 28628c2ecf20Sopenharmony_ci .ndo_select_queue = mlx4_en_select_queue, 28638c2ecf20Sopenharmony_ci .ndo_get_stats64 = mlx4_en_get_stats64, 28648c2ecf20Sopenharmony_ci .ndo_set_rx_mode = mlx4_en_set_rx_mode, 28658c2ecf20Sopenharmony_ci .ndo_set_mac_address = mlx4_en_set_mac, 28668c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 28678c2ecf20Sopenharmony_ci .ndo_change_mtu = mlx4_en_change_mtu, 28688c2ecf20Sopenharmony_ci .ndo_tx_timeout = mlx4_en_tx_timeout, 28698c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid, 28708c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, 28718c2ecf20Sopenharmony_ci .ndo_set_vf_mac = mlx4_en_set_vf_mac, 28728c2ecf20Sopenharmony_ci .ndo_set_vf_vlan = mlx4_en_set_vf_vlan, 28738c2ecf20Sopenharmony_ci .ndo_set_vf_rate = mlx4_en_set_vf_rate, 28748c2ecf20Sopenharmony_ci .ndo_set_vf_spoofchk = mlx4_en_set_vf_spoofchk, 28758c2ecf20Sopenharmony_ci .ndo_set_vf_link_state = mlx4_en_set_vf_link_state, 28768c2ecf20Sopenharmony_ci .ndo_get_vf_stats = mlx4_en_get_vf_stats, 28778c2ecf20Sopenharmony_ci .ndo_get_vf_config = mlx4_en_get_vf_config, 28788c2ecf20Sopenharmony_ci .ndo_set_features = mlx4_en_set_features, 28798c2ecf20Sopenharmony_ci .ndo_fix_features = mlx4_en_fix_features, 28808c2ecf20Sopenharmony_ci .ndo_setup_tc = __mlx4_en_setup_tc, 28818c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 28828c2ecf20Sopenharmony_ci .ndo_rx_flow_steer = mlx4_en_filter_rfs, 28838c2ecf20Sopenharmony_ci#endif 28848c2ecf20Sopenharmony_ci .ndo_get_phys_port_id = mlx4_en_get_phys_port_id, 28858c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 28868c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 28878c2ecf20Sopenharmony_ci .ndo_features_check = mlx4_en_features_check, 28888c2ecf20Sopenharmony_ci .ndo_set_tx_maxrate = mlx4_en_set_tx_maxrate, 28898c2ecf20Sopenharmony_ci .ndo_bpf = mlx4_xdp, 28908c2ecf20Sopenharmony_ci}; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_cistruct mlx4_en_bond { 28938c2ecf20Sopenharmony_ci struct work_struct work; 28948c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv; 28958c2ecf20Sopenharmony_ci int is_bonded; 28968c2ecf20Sopenharmony_ci struct mlx4_port_map port_map; 28978c2ecf20Sopenharmony_ci}; 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_cistatic void mlx4_en_bond_work(struct work_struct *work) 29008c2ecf20Sopenharmony_ci{ 29018c2ecf20Sopenharmony_ci struct mlx4_en_bond *bond = container_of(work, 29028c2ecf20Sopenharmony_ci struct mlx4_en_bond, 29038c2ecf20Sopenharmony_ci work); 29048c2ecf20Sopenharmony_ci int err = 0; 29058c2ecf20Sopenharmony_ci struct mlx4_dev *dev = bond->priv->mdev->dev; 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_ci if (bond->is_bonded) { 29088c2ecf20Sopenharmony_ci if (!mlx4_is_bonded(dev)) { 29098c2ecf20Sopenharmony_ci err = mlx4_bond(dev); 29108c2ecf20Sopenharmony_ci if (err) 29118c2ecf20Sopenharmony_ci en_err(bond->priv, "Fail to bond device\n"); 29128c2ecf20Sopenharmony_ci } 29138c2ecf20Sopenharmony_ci if (!err) { 29148c2ecf20Sopenharmony_ci err = mlx4_port_map_set(dev, &bond->port_map); 29158c2ecf20Sopenharmony_ci if (err) 29168c2ecf20Sopenharmony_ci en_err(bond->priv, "Fail to set port map [%d][%d]: %d\n", 29178c2ecf20Sopenharmony_ci bond->port_map.port1, 29188c2ecf20Sopenharmony_ci bond->port_map.port2, 29198c2ecf20Sopenharmony_ci err); 29208c2ecf20Sopenharmony_ci } 29218c2ecf20Sopenharmony_ci } else if (mlx4_is_bonded(dev)) { 29228c2ecf20Sopenharmony_ci err = mlx4_unbond(dev); 29238c2ecf20Sopenharmony_ci if (err) 29248c2ecf20Sopenharmony_ci en_err(bond->priv, "Fail to unbond device\n"); 29258c2ecf20Sopenharmony_ci } 29268c2ecf20Sopenharmony_ci dev_put(bond->priv->dev); 29278c2ecf20Sopenharmony_ci kfree(bond); 29288c2ecf20Sopenharmony_ci} 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_cistatic int mlx4_en_queue_bond_work(struct mlx4_en_priv *priv, int is_bonded, 29318c2ecf20Sopenharmony_ci u8 v2p_p1, u8 v2p_p2) 29328c2ecf20Sopenharmony_ci{ 29338c2ecf20Sopenharmony_ci struct mlx4_en_bond *bond = NULL; 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci bond = kzalloc(sizeof(*bond), GFP_ATOMIC); 29368c2ecf20Sopenharmony_ci if (!bond) 29378c2ecf20Sopenharmony_ci return -ENOMEM; 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci INIT_WORK(&bond->work, mlx4_en_bond_work); 29408c2ecf20Sopenharmony_ci bond->priv = priv; 29418c2ecf20Sopenharmony_ci bond->is_bonded = is_bonded; 29428c2ecf20Sopenharmony_ci bond->port_map.port1 = v2p_p1; 29438c2ecf20Sopenharmony_ci bond->port_map.port2 = v2p_p2; 29448c2ecf20Sopenharmony_ci dev_hold(priv->dev); 29458c2ecf20Sopenharmony_ci queue_work(priv->mdev->workqueue, &bond->work); 29468c2ecf20Sopenharmony_ci return 0; 29478c2ecf20Sopenharmony_ci} 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ciint mlx4_en_netdev_event(struct notifier_block *this, 29508c2ecf20Sopenharmony_ci unsigned long event, void *ptr) 29518c2ecf20Sopenharmony_ci{ 29528c2ecf20Sopenharmony_ci struct net_device *ndev = netdev_notifier_info_to_dev(ptr); 29538c2ecf20Sopenharmony_ci u8 port = 0; 29548c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev; 29558c2ecf20Sopenharmony_ci struct mlx4_dev *dev; 29568c2ecf20Sopenharmony_ci int i, num_eth_ports = 0; 29578c2ecf20Sopenharmony_ci bool do_bond = true; 29588c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv; 29598c2ecf20Sopenharmony_ci u8 v2p_port1 = 0; 29608c2ecf20Sopenharmony_ci u8 v2p_port2 = 0; 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci if (!net_eq(dev_net(ndev), &init_net)) 29638c2ecf20Sopenharmony_ci return NOTIFY_DONE; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci mdev = container_of(this, struct mlx4_en_dev, nb); 29668c2ecf20Sopenharmony_ci dev = mdev->dev; 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci /* Go into this mode only when two network devices set on two ports 29698c2ecf20Sopenharmony_ci * of the same mlx4 device are slaves of the same bonding master 29708c2ecf20Sopenharmony_ci */ 29718c2ecf20Sopenharmony_ci mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { 29728c2ecf20Sopenharmony_ci ++num_eth_ports; 29738c2ecf20Sopenharmony_ci if (!port && (mdev->pndev[i] == ndev)) 29748c2ecf20Sopenharmony_ci port = i; 29758c2ecf20Sopenharmony_ci mdev->upper[i] = mdev->pndev[i] ? 29768c2ecf20Sopenharmony_ci netdev_master_upper_dev_get(mdev->pndev[i]) : NULL; 29778c2ecf20Sopenharmony_ci /* condition not met: network device is a slave */ 29788c2ecf20Sopenharmony_ci if (!mdev->upper[i]) 29798c2ecf20Sopenharmony_ci do_bond = false; 29808c2ecf20Sopenharmony_ci if (num_eth_ports < 2) 29818c2ecf20Sopenharmony_ci continue; 29828c2ecf20Sopenharmony_ci /* condition not met: same master */ 29838c2ecf20Sopenharmony_ci if (mdev->upper[i] != mdev->upper[i-1]) 29848c2ecf20Sopenharmony_ci do_bond = false; 29858c2ecf20Sopenharmony_ci } 29868c2ecf20Sopenharmony_ci /* condition not met: 2 salves */ 29878c2ecf20Sopenharmony_ci do_bond = (num_eth_ports == 2) ? do_bond : false; 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci /* handle only events that come with enough info */ 29908c2ecf20Sopenharmony_ci if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port) 29918c2ecf20Sopenharmony_ci return NOTIFY_DONE; 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci priv = netdev_priv(ndev); 29948c2ecf20Sopenharmony_ci if (do_bond) { 29958c2ecf20Sopenharmony_ci struct netdev_notifier_bonding_info *notifier_info = ptr; 29968c2ecf20Sopenharmony_ci struct netdev_bonding_info *bonding_info = 29978c2ecf20Sopenharmony_ci ¬ifier_info->bonding_info; 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci /* required mode 1, 2 or 4 */ 30008c2ecf20Sopenharmony_ci if ((bonding_info->master.bond_mode != BOND_MODE_ACTIVEBACKUP) && 30018c2ecf20Sopenharmony_ci (bonding_info->master.bond_mode != BOND_MODE_XOR) && 30028c2ecf20Sopenharmony_ci (bonding_info->master.bond_mode != BOND_MODE_8023AD)) 30038c2ecf20Sopenharmony_ci do_bond = false; 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci /* require exactly 2 slaves */ 30068c2ecf20Sopenharmony_ci if (bonding_info->master.num_slaves != 2) 30078c2ecf20Sopenharmony_ci do_bond = false; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci /* calc v2p */ 30108c2ecf20Sopenharmony_ci if (do_bond) { 30118c2ecf20Sopenharmony_ci if (bonding_info->master.bond_mode == 30128c2ecf20Sopenharmony_ci BOND_MODE_ACTIVEBACKUP) { 30138c2ecf20Sopenharmony_ci /* in active-backup mode virtual ports are 30148c2ecf20Sopenharmony_ci * mapped to the physical port of the active 30158c2ecf20Sopenharmony_ci * slave */ 30168c2ecf20Sopenharmony_ci if (bonding_info->slave.state == 30178c2ecf20Sopenharmony_ci BOND_STATE_BACKUP) { 30188c2ecf20Sopenharmony_ci if (port == 1) { 30198c2ecf20Sopenharmony_ci v2p_port1 = 2; 30208c2ecf20Sopenharmony_ci v2p_port2 = 2; 30218c2ecf20Sopenharmony_ci } else { 30228c2ecf20Sopenharmony_ci v2p_port1 = 1; 30238c2ecf20Sopenharmony_ci v2p_port2 = 1; 30248c2ecf20Sopenharmony_ci } 30258c2ecf20Sopenharmony_ci } else { /* BOND_STATE_ACTIVE */ 30268c2ecf20Sopenharmony_ci if (port == 1) { 30278c2ecf20Sopenharmony_ci v2p_port1 = 1; 30288c2ecf20Sopenharmony_ci v2p_port2 = 1; 30298c2ecf20Sopenharmony_ci } else { 30308c2ecf20Sopenharmony_ci v2p_port1 = 2; 30318c2ecf20Sopenharmony_ci v2p_port2 = 2; 30328c2ecf20Sopenharmony_ci } 30338c2ecf20Sopenharmony_ci } 30348c2ecf20Sopenharmony_ci } else { /* Active-Active */ 30358c2ecf20Sopenharmony_ci /* in active-active mode a virtual port is 30368c2ecf20Sopenharmony_ci * mapped to the native physical port if and only 30378c2ecf20Sopenharmony_ci * if the physical port is up */ 30388c2ecf20Sopenharmony_ci __s8 link = bonding_info->slave.link; 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci if (port == 1) 30418c2ecf20Sopenharmony_ci v2p_port2 = 2; 30428c2ecf20Sopenharmony_ci else 30438c2ecf20Sopenharmony_ci v2p_port1 = 1; 30448c2ecf20Sopenharmony_ci if ((link == BOND_LINK_UP) || 30458c2ecf20Sopenharmony_ci (link == BOND_LINK_FAIL)) { 30468c2ecf20Sopenharmony_ci if (port == 1) 30478c2ecf20Sopenharmony_ci v2p_port1 = 1; 30488c2ecf20Sopenharmony_ci else 30498c2ecf20Sopenharmony_ci v2p_port2 = 2; 30508c2ecf20Sopenharmony_ci } else { /* BOND_LINK_DOWN || BOND_LINK_BACK */ 30518c2ecf20Sopenharmony_ci if (port == 1) 30528c2ecf20Sopenharmony_ci v2p_port1 = 2; 30538c2ecf20Sopenharmony_ci else 30548c2ecf20Sopenharmony_ci v2p_port2 = 1; 30558c2ecf20Sopenharmony_ci } 30568c2ecf20Sopenharmony_ci } 30578c2ecf20Sopenharmony_ci } 30588c2ecf20Sopenharmony_ci } 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci mlx4_en_queue_bond_work(priv, do_bond, 30618c2ecf20Sopenharmony_ci v2p_port1, v2p_port2); 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci return NOTIFY_DONE; 30648c2ecf20Sopenharmony_ci} 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_civoid mlx4_en_update_pfc_stats_bitmap(struct mlx4_dev *dev, 30678c2ecf20Sopenharmony_ci struct mlx4_en_stats_bitmap *stats_bitmap, 30688c2ecf20Sopenharmony_ci u8 rx_ppp, u8 rx_pause, 30698c2ecf20Sopenharmony_ci u8 tx_ppp, u8 tx_pause) 30708c2ecf20Sopenharmony_ci{ 30718c2ecf20Sopenharmony_ci int last_i = NUM_MAIN_STATS + NUM_PORT_STATS + NUM_PF_STATS; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci if (!mlx4_is_slave(dev) && 30748c2ecf20Sopenharmony_ci (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN)) { 30758c2ecf20Sopenharmony_ci mutex_lock(&stats_bitmap->mutex); 30768c2ecf20Sopenharmony_ci bitmap_clear(stats_bitmap->bitmap, last_i, NUM_FLOW_STATS); 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci if (rx_ppp) 30798c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 30808c2ecf20Sopenharmony_ci NUM_FLOW_PRIORITY_STATS_RX); 30818c2ecf20Sopenharmony_ci last_i += NUM_FLOW_PRIORITY_STATS_RX; 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci if (rx_pause && !(rx_ppp)) 30848c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 30858c2ecf20Sopenharmony_ci NUM_FLOW_STATS_RX); 30868c2ecf20Sopenharmony_ci last_i += NUM_FLOW_STATS_RX; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci if (tx_ppp) 30898c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 30908c2ecf20Sopenharmony_ci NUM_FLOW_PRIORITY_STATS_TX); 30918c2ecf20Sopenharmony_ci last_i += NUM_FLOW_PRIORITY_STATS_TX; 30928c2ecf20Sopenharmony_ci 30938c2ecf20Sopenharmony_ci if (tx_pause && !(tx_ppp)) 30948c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 30958c2ecf20Sopenharmony_ci NUM_FLOW_STATS_TX); 30968c2ecf20Sopenharmony_ci last_i += NUM_FLOW_STATS_TX; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci mutex_unlock(&stats_bitmap->mutex); 30998c2ecf20Sopenharmony_ci } 31008c2ecf20Sopenharmony_ci} 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_civoid mlx4_en_set_stats_bitmap(struct mlx4_dev *dev, 31038c2ecf20Sopenharmony_ci struct mlx4_en_stats_bitmap *stats_bitmap, 31048c2ecf20Sopenharmony_ci u8 rx_ppp, u8 rx_pause, 31058c2ecf20Sopenharmony_ci u8 tx_ppp, u8 tx_pause) 31068c2ecf20Sopenharmony_ci{ 31078c2ecf20Sopenharmony_ci int last_i = 0; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci mutex_init(&stats_bitmap->mutex); 31108c2ecf20Sopenharmony_ci bitmap_zero(stats_bitmap->bitmap, NUM_ALL_STATS); 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci if (mlx4_is_slave(dev)) { 31138c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 31148c2ecf20Sopenharmony_ci MLX4_FIND_NETDEV_STAT(rx_packets), 1); 31158c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 31168c2ecf20Sopenharmony_ci MLX4_FIND_NETDEV_STAT(tx_packets), 1); 31178c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 31188c2ecf20Sopenharmony_ci MLX4_FIND_NETDEV_STAT(rx_bytes), 1); 31198c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 31208c2ecf20Sopenharmony_ci MLX4_FIND_NETDEV_STAT(tx_bytes), 1); 31218c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 31228c2ecf20Sopenharmony_ci MLX4_FIND_NETDEV_STAT(rx_dropped), 1); 31238c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i + 31248c2ecf20Sopenharmony_ci MLX4_FIND_NETDEV_STAT(tx_dropped), 1); 31258c2ecf20Sopenharmony_ci } else { 31268c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_MAIN_STATS); 31278c2ecf20Sopenharmony_ci } 31288c2ecf20Sopenharmony_ci last_i += NUM_MAIN_STATS; 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_PORT_STATS); 31318c2ecf20Sopenharmony_ci last_i += NUM_PORT_STATS; 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci if (mlx4_is_master(dev)) 31348c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, 31358c2ecf20Sopenharmony_ci NUM_PF_STATS); 31368c2ecf20Sopenharmony_ci last_i += NUM_PF_STATS; 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci mlx4_en_update_pfc_stats_bitmap(dev, stats_bitmap, 31398c2ecf20Sopenharmony_ci rx_ppp, rx_pause, 31408c2ecf20Sopenharmony_ci tx_ppp, tx_pause); 31418c2ecf20Sopenharmony_ci last_i += NUM_FLOW_STATS; 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_ci if (!mlx4_is_slave(dev)) 31448c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_PKT_STATS); 31458c2ecf20Sopenharmony_ci last_i += NUM_PKT_STATS; 31468c2ecf20Sopenharmony_ci 31478c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_XDP_STATS); 31488c2ecf20Sopenharmony_ci last_i += NUM_XDP_STATS; 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci if (!mlx4_is_slave(dev)) 31518c2ecf20Sopenharmony_ci bitmap_set(stats_bitmap->bitmap, last_i, NUM_PHY_STATS); 31528c2ecf20Sopenharmony_ci last_i += NUM_PHY_STATS; 31538c2ecf20Sopenharmony_ci} 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ciint mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, 31568c2ecf20Sopenharmony_ci struct mlx4_en_port_profile *prof) 31578c2ecf20Sopenharmony_ci{ 31588c2ecf20Sopenharmony_ci struct net_device *dev; 31598c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv; 31608c2ecf20Sopenharmony_ci int i, t; 31618c2ecf20Sopenharmony_ci int err; 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ci dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv), 31648c2ecf20Sopenharmony_ci MAX_TX_RINGS, MAX_RX_RINGS); 31658c2ecf20Sopenharmony_ci if (dev == NULL) 31668c2ecf20Sopenharmony_ci return -ENOMEM; 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(dev, prof->tx_ring_num[TX]); 31698c2ecf20Sopenharmony_ci netif_set_real_num_rx_queues(dev, prof->rx_ring_num); 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &mdev->dev->persist->pdev->dev); 31728c2ecf20Sopenharmony_ci dev->dev_port = port - 1; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci /* 31758c2ecf20Sopenharmony_ci * Initialize driver private data 31768c2ecf20Sopenharmony_ci */ 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 31798c2ecf20Sopenharmony_ci memset(priv, 0, sizeof(struct mlx4_en_priv)); 31808c2ecf20Sopenharmony_ci priv->counter_index = MLX4_SINK_COUNTER_INDEX(mdev->dev); 31818c2ecf20Sopenharmony_ci spin_lock_init(&priv->stats_lock); 31828c2ecf20Sopenharmony_ci INIT_WORK(&priv->rx_mode_task, mlx4_en_do_set_rx_mode); 31838c2ecf20Sopenharmony_ci INIT_WORK(&priv->restart_task, mlx4_en_restart); 31848c2ecf20Sopenharmony_ci INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate); 31858c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats); 31868c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task); 31878c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 31888c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->filters); 31898c2ecf20Sopenharmony_ci spin_lock_init(&priv->filters_lock); 31908c2ecf20Sopenharmony_ci#endif 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci priv->dev = dev; 31938c2ecf20Sopenharmony_ci priv->mdev = mdev; 31948c2ecf20Sopenharmony_ci priv->ddev = &mdev->pdev->dev; 31958c2ecf20Sopenharmony_ci priv->prof = prof; 31968c2ecf20Sopenharmony_ci priv->port = port; 31978c2ecf20Sopenharmony_ci priv->port_up = false; 31988c2ecf20Sopenharmony_ci priv->flags = prof->flags; 31998c2ecf20Sopenharmony_ci priv->pflags = MLX4_EN_PRIV_FLAGS_BLUEFLAME; 32008c2ecf20Sopenharmony_ci priv->ctrl_flags = cpu_to_be32(MLX4_WQE_CTRL_CQ_UPDATE | 32018c2ecf20Sopenharmony_ci MLX4_WQE_CTRL_SOLICITED); 32028c2ecf20Sopenharmony_ci priv->num_tx_rings_p_up = mdev->profile.max_num_tx_rings_p_up; 32038c2ecf20Sopenharmony_ci priv->tx_work_limit = MLX4_EN_DEFAULT_TX_WORK; 32048c2ecf20Sopenharmony_ci netdev_rss_key_fill(priv->rss_key, sizeof(priv->rss_key)); 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_ci for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { 32078c2ecf20Sopenharmony_ci priv->tx_ring_num[t] = prof->tx_ring_num[t]; 32088c2ecf20Sopenharmony_ci if (!priv->tx_ring_num[t]) 32098c2ecf20Sopenharmony_ci continue; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci priv->tx_ring[t] = kcalloc(MAX_TX_RINGS, 32128c2ecf20Sopenharmony_ci sizeof(struct mlx4_en_tx_ring *), 32138c2ecf20Sopenharmony_ci GFP_KERNEL); 32148c2ecf20Sopenharmony_ci if (!priv->tx_ring[t]) { 32158c2ecf20Sopenharmony_ci err = -ENOMEM; 32168c2ecf20Sopenharmony_ci goto out; 32178c2ecf20Sopenharmony_ci } 32188c2ecf20Sopenharmony_ci priv->tx_cq[t] = kcalloc(MAX_TX_RINGS, 32198c2ecf20Sopenharmony_ci sizeof(struct mlx4_en_cq *), 32208c2ecf20Sopenharmony_ci GFP_KERNEL); 32218c2ecf20Sopenharmony_ci if (!priv->tx_cq[t]) { 32228c2ecf20Sopenharmony_ci err = -ENOMEM; 32238c2ecf20Sopenharmony_ci goto out; 32248c2ecf20Sopenharmony_ci } 32258c2ecf20Sopenharmony_ci } 32268c2ecf20Sopenharmony_ci priv->rx_ring_num = prof->rx_ring_num; 32278c2ecf20Sopenharmony_ci priv->cqe_factor = (mdev->dev->caps.cqe_size == 64) ? 1 : 0; 32288c2ecf20Sopenharmony_ci priv->cqe_size = mdev->dev->caps.cqe_size; 32298c2ecf20Sopenharmony_ci priv->mac_index = -1; 32308c2ecf20Sopenharmony_ci priv->msg_enable = MLX4_EN_MSG_LEVEL; 32318c2ecf20Sopenharmony_ci#ifdef CONFIG_MLX4_EN_DCB 32328c2ecf20Sopenharmony_ci if (!mlx4_is_slave(priv->mdev->dev)) { 32338c2ecf20Sopenharmony_ci u8 prio; 32348c2ecf20Sopenharmony_ci 32358c2ecf20Sopenharmony_ci for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; ++prio) { 32368c2ecf20Sopenharmony_ci priv->ets.prio_tc[prio] = prio; 32378c2ecf20Sopenharmony_ci priv->ets.tc_tsa[prio] = IEEE_8021QAZ_TSA_VENDOR; 32388c2ecf20Sopenharmony_ci } 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci priv->dcbx_cap = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_HOST | 32418c2ecf20Sopenharmony_ci DCB_CAP_DCBX_VER_IEEE; 32428c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_DCB_ENABLED; 32438c2ecf20Sopenharmony_ci priv->cee_config.pfc_state = false; 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_EN_NUM_UP_HIGH; i++) 32468c2ecf20Sopenharmony_ci priv->cee_config.dcb_pfc[i] = pfc_disabled; 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) { 32498c2ecf20Sopenharmony_ci dev->dcbnl_ops = &mlx4_en_dcbnl_ops; 32508c2ecf20Sopenharmony_ci } else { 32518c2ecf20Sopenharmony_ci en_info(priv, "enabling only PFC DCB ops\n"); 32528c2ecf20Sopenharmony_ci dev->dcbnl_ops = &mlx4_en_dcbnl_pfc_ops; 32538c2ecf20Sopenharmony_ci } 32548c2ecf20Sopenharmony_ci } 32558c2ecf20Sopenharmony_ci#endif 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) 32588c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&priv->mac_hash[i]); 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ci /* Query for default mac and max mtu */ 32618c2ecf20Sopenharmony_ci priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci if (mdev->dev->caps.rx_checksum_flags_port[priv->port] & 32648c2ecf20Sopenharmony_ci MLX4_RX_CSUM_MODE_VAL_NON_TCP_UDP) 32658c2ecf20Sopenharmony_ci priv->flags |= MLX4_EN_FLAG_RX_CSUM_NON_TCP_UDP; 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci /* Set default MAC */ 32688c2ecf20Sopenharmony_ci dev->addr_len = ETH_ALEN; 32698c2ecf20Sopenharmony_ci mlx4_en_u64_to_mac(dev->dev_addr, mdev->dev->caps.def_mac[priv->port]); 32708c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(dev->dev_addr)) { 32718c2ecf20Sopenharmony_ci en_err(priv, "Port: %d, invalid mac burned: %pM, quitting\n", 32728c2ecf20Sopenharmony_ci priv->port, dev->dev_addr); 32738c2ecf20Sopenharmony_ci err = -EINVAL; 32748c2ecf20Sopenharmony_ci goto out; 32758c2ecf20Sopenharmony_ci } else if (mlx4_is_slave(priv->mdev->dev) && 32768c2ecf20Sopenharmony_ci (priv->mdev->dev->port_random_macs & 1 << priv->port)) { 32778c2ecf20Sopenharmony_ci /* Random MAC was assigned in mlx4_slave_cap 32788c2ecf20Sopenharmony_ci * in mlx4_core module 32798c2ecf20Sopenharmony_ci */ 32808c2ecf20Sopenharmony_ci dev->addr_assign_type |= NET_ADDR_RANDOM; 32818c2ecf20Sopenharmony_ci en_warn(priv, "Assigned random MAC address %pM\n", dev->dev_addr); 32828c2ecf20Sopenharmony_ci } 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci memcpy(priv->current_mac, dev->dev_addr, sizeof(priv->current_mac)); 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci priv->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) + 32878c2ecf20Sopenharmony_ci DS_SIZE * MLX4_EN_MAX_RX_FRAGS); 32888c2ecf20Sopenharmony_ci err = mlx4_en_alloc_resources(priv); 32898c2ecf20Sopenharmony_ci if (err) 32908c2ecf20Sopenharmony_ci goto out; 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci /* Initialize time stamping config */ 32938c2ecf20Sopenharmony_ci priv->hwtstamp_config.flags = 0; 32948c2ecf20Sopenharmony_ci priv->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF; 32958c2ecf20Sopenharmony_ci priv->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci /* Allocate page for receive rings */ 32988c2ecf20Sopenharmony_ci err = mlx4_alloc_hwq_res(mdev->dev, &priv->res, 32998c2ecf20Sopenharmony_ci MLX4_EN_PAGE_SIZE); 33008c2ecf20Sopenharmony_ci if (err) { 33018c2ecf20Sopenharmony_ci en_err(priv, "Failed to allocate page for rx qps\n"); 33028c2ecf20Sopenharmony_ci goto out; 33038c2ecf20Sopenharmony_ci } 33048c2ecf20Sopenharmony_ci priv->allocated = 1; 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci /* 33078c2ecf20Sopenharmony_ci * Initialize netdev entry points 33088c2ecf20Sopenharmony_ci */ 33098c2ecf20Sopenharmony_ci if (mlx4_is_master(priv->mdev->dev)) 33108c2ecf20Sopenharmony_ci dev->netdev_ops = &mlx4_netdev_ops_master; 33118c2ecf20Sopenharmony_ci else 33128c2ecf20Sopenharmony_ci dev->netdev_ops = &mlx4_netdev_ops; 33138c2ecf20Sopenharmony_ci dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT; 33148c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(dev, priv->tx_ring_num[TX]); 33158c2ecf20Sopenharmony_ci netif_set_real_num_rx_queues(dev, priv->rx_ring_num); 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci dev->ethtool_ops = &mlx4_en_ethtool_ops; 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci /* 33208c2ecf20Sopenharmony_ci * Set driver features 33218c2ecf20Sopenharmony_ci */ 33228c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; 33238c2ecf20Sopenharmony_ci if (mdev->LSO_support) 33248c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci if (mdev->dev->caps.tunnel_offload_mode == 33278c2ecf20Sopenharmony_ci MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) { 33288c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL | 33298c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 33308c2ecf20Sopenharmony_ci NETIF_F_GSO_PARTIAL; 33318c2ecf20Sopenharmony_ci dev->features |= NETIF_F_GSO_UDP_TUNNEL | 33328c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 33338c2ecf20Sopenharmony_ci NETIF_F_GSO_PARTIAL; 33348c2ecf20Sopenharmony_ci dev->gso_partial_features = NETIF_F_GSO_UDP_TUNNEL_CSUM; 33358c2ecf20Sopenharmony_ci dev->hw_enc_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 33368c2ecf20Sopenharmony_ci NETIF_F_RXCSUM | 33378c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6 | 33388c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL | 33398c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 33408c2ecf20Sopenharmony_ci NETIF_F_GSO_PARTIAL; 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci dev->udp_tunnel_nic_info = &mlx4_udp_tunnels; 33438c2ecf20Sopenharmony_ci } 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci dev->vlan_features = dev->hw_features; 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_RXHASH; 33488c2ecf20Sopenharmony_ci dev->features = dev->hw_features | NETIF_F_HIGHDMA | 33498c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | 33508c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER; 33518c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_LOOPBACK | 33528c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) { 33558c2ecf20Sopenharmony_ci dev->features |= NETIF_F_HW_VLAN_STAG_RX | 33568c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_STAG_FILTER; 33578c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_HW_VLAN_STAG_RX; 33588c2ecf20Sopenharmony_ci } 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci if (mlx4_is_slave(mdev->dev)) { 33618c2ecf20Sopenharmony_ci bool vlan_offload_disabled; 33628c2ecf20Sopenharmony_ci int phv; 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci err = get_phv_bit(mdev->dev, port, &phv); 33658c2ecf20Sopenharmony_ci if (!err && phv) { 33668c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX; 33678c2ecf20Sopenharmony_ci priv->pflags |= MLX4_EN_PRIV_FLAGS_PHV; 33688c2ecf20Sopenharmony_ci } 33698c2ecf20Sopenharmony_ci err = mlx4_get_is_vlan_offload_disabled(mdev->dev, port, 33708c2ecf20Sopenharmony_ci &vlan_offload_disabled); 33718c2ecf20Sopenharmony_ci if (!err && vlan_offload_disabled) { 33728c2ecf20Sopenharmony_ci dev->hw_features &= ~(NETIF_F_HW_VLAN_CTAG_TX | 33738c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | 33748c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX | 33758c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_STAG_RX); 33768c2ecf20Sopenharmony_ci dev->features &= ~(NETIF_F_HW_VLAN_CTAG_TX | 33778c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | 33788c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX | 33798c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_STAG_RX); 33808c2ecf20Sopenharmony_ci } 33818c2ecf20Sopenharmony_ci } else { 33828c2ecf20Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN && 33838c2ecf20Sopenharmony_ci !(mdev->dev->caps.flags2 & 33848c2ecf20Sopenharmony_ci MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) 33858c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX; 33868c2ecf20Sopenharmony_ci } 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) 33898c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_RXFCS; 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_IGNORE_FCS) 33928c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_RXALL; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci if (mdev->dev->caps.steering_mode == 33958c2ecf20Sopenharmony_ci MLX4_STEERING_MODE_DEVICE_MANAGED && 33968c2ecf20Sopenharmony_ci mdev->dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC) 33978c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_NTUPLE; 33988c2ecf20Sopenharmony_ci 33998c2ecf20Sopenharmony_ci if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0) 34008c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_UNICAST_FLT; 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci /* Setting a default hash function value */ 34038c2ecf20Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_TOP) { 34048c2ecf20Sopenharmony_ci priv->rss_hash_fn = ETH_RSS_HASH_TOP; 34058c2ecf20Sopenharmony_ci } else if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RSS_XOR) { 34068c2ecf20Sopenharmony_ci priv->rss_hash_fn = ETH_RSS_HASH_XOR; 34078c2ecf20Sopenharmony_ci } else { 34088c2ecf20Sopenharmony_ci en_warn(priv, 34098c2ecf20Sopenharmony_ci "No RSS hash capabilities exposed, using Toeplitz\n"); 34108c2ecf20Sopenharmony_ci priv->rss_hash_fn = ETH_RSS_HASH_TOP; 34118c2ecf20Sopenharmony_ci } 34128c2ecf20Sopenharmony_ci 34138c2ecf20Sopenharmony_ci /* MTU range: 68 - hw-specific max */ 34148c2ecf20Sopenharmony_ci dev->min_mtu = ETH_MIN_MTU; 34158c2ecf20Sopenharmony_ci dev->max_mtu = priv->max_mtu; 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci mdev->pndev[port] = dev; 34188c2ecf20Sopenharmony_ci mdev->upper[port] = NULL; 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci netif_carrier_off(dev); 34218c2ecf20Sopenharmony_ci mlx4_en_set_default_moderation(priv); 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num[TX]); 34248c2ecf20Sopenharmony_ci en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num); 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci mlx4_en_update_loopback_state(priv->dev, priv->dev->features); 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ci /* Configure port */ 34298c2ecf20Sopenharmony_ci mlx4_en_calc_rx_buf(dev); 34308c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_general(mdev->dev, priv->port, 34318c2ecf20Sopenharmony_ci priv->rx_skb_size + ETH_FCS_LEN, 34328c2ecf20Sopenharmony_ci prof->tx_pause, prof->tx_ppp, 34338c2ecf20Sopenharmony_ci prof->rx_pause, prof->rx_ppp); 34348c2ecf20Sopenharmony_ci if (err) { 34358c2ecf20Sopenharmony_ci en_err(priv, "Failed setting port general configurations for port %d, with error %d\n", 34368c2ecf20Sopenharmony_ci priv->port, err); 34378c2ecf20Sopenharmony_ci goto out; 34388c2ecf20Sopenharmony_ci } 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci if (mdev->dev->caps.tunnel_offload_mode == MLX4_TUNNEL_OFFLOAD_MODE_VXLAN) { 34418c2ecf20Sopenharmony_ci err = mlx4_SET_PORT_VXLAN(mdev->dev, priv->port, VXLAN_STEER_BY_OUTER_MAC, 1); 34428c2ecf20Sopenharmony_ci if (err) { 34438c2ecf20Sopenharmony_ci en_err(priv, "Failed setting port L2 tunnel configuration, err %d\n", 34448c2ecf20Sopenharmony_ci err); 34458c2ecf20Sopenharmony_ci goto out; 34468c2ecf20Sopenharmony_ci } 34478c2ecf20Sopenharmony_ci } 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci /* Init port */ 34508c2ecf20Sopenharmony_ci en_warn(priv, "Initializing port\n"); 34518c2ecf20Sopenharmony_ci err = mlx4_INIT_PORT(mdev->dev, priv->port); 34528c2ecf20Sopenharmony_ci if (err) { 34538c2ecf20Sopenharmony_ci en_err(priv, "Failed Initializing port\n"); 34548c2ecf20Sopenharmony_ci goto out; 34558c2ecf20Sopenharmony_ci } 34568c2ecf20Sopenharmony_ci queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY); 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci /* Initialize time stamp mechanism */ 34598c2ecf20Sopenharmony_ci if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) 34608c2ecf20Sopenharmony_ci mlx4_en_init_timestamp(mdev); 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci queue_delayed_work(mdev->workqueue, &priv->service_task, 34638c2ecf20Sopenharmony_ci SERVICE_TASK_DELAY); 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci mlx4_en_set_stats_bitmap(mdev->dev, &priv->stats_bitmap, 34668c2ecf20Sopenharmony_ci mdev->profile.prof[priv->port].rx_ppp, 34678c2ecf20Sopenharmony_ci mdev->profile.prof[priv->port].rx_pause, 34688c2ecf20Sopenharmony_ci mdev->profile.prof[priv->port].tx_ppp, 34698c2ecf20Sopenharmony_ci mdev->profile.prof[priv->port].tx_pause); 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci err = register_netdev(dev); 34728c2ecf20Sopenharmony_ci if (err) { 34738c2ecf20Sopenharmony_ci en_err(priv, "Netdev registration failed for port %d\n", port); 34748c2ecf20Sopenharmony_ci goto out; 34758c2ecf20Sopenharmony_ci } 34768c2ecf20Sopenharmony_ci 34778c2ecf20Sopenharmony_ci priv->registered = 1; 34788c2ecf20Sopenharmony_ci devlink_port_type_eth_set(mlx4_get_devlink_port(mdev->dev, priv->port), 34798c2ecf20Sopenharmony_ci dev); 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci return 0; 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ciout: 34848c2ecf20Sopenharmony_ci mlx4_en_destroy_netdev(dev); 34858c2ecf20Sopenharmony_ci return err; 34868c2ecf20Sopenharmony_ci} 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ciint mlx4_en_reset_config(struct net_device *dev, 34898c2ecf20Sopenharmony_ci struct hwtstamp_config ts_config, 34908c2ecf20Sopenharmony_ci netdev_features_t features) 34918c2ecf20Sopenharmony_ci{ 34928c2ecf20Sopenharmony_ci struct mlx4_en_priv *priv = netdev_priv(dev); 34938c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 34948c2ecf20Sopenharmony_ci struct mlx4_en_port_profile new_prof; 34958c2ecf20Sopenharmony_ci struct mlx4_en_priv *tmp; 34968c2ecf20Sopenharmony_ci int port_up = 0; 34978c2ecf20Sopenharmony_ci int err = 0; 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci if (priv->hwtstamp_config.tx_type == ts_config.tx_type && 35008c2ecf20Sopenharmony_ci priv->hwtstamp_config.rx_filter == ts_config.rx_filter && 35018c2ecf20Sopenharmony_ci !DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX) && 35028c2ecf20Sopenharmony_ci !DEV_FEATURE_CHANGED(dev, features, NETIF_F_RXFCS)) 35038c2ecf20Sopenharmony_ci return 0; /* Nothing to change */ 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX) && 35068c2ecf20Sopenharmony_ci (features & NETIF_F_HW_VLAN_CTAG_RX) && 35078c2ecf20Sopenharmony_ci (priv->hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE)) { 35088c2ecf20Sopenharmony_ci en_warn(priv, "Can't turn ON rx vlan offload while time-stamping rx filter is ON\n"); 35098c2ecf20Sopenharmony_ci return -EINVAL; 35108c2ecf20Sopenharmony_ci } 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 35138c2ecf20Sopenharmony_ci if (!tmp) 35148c2ecf20Sopenharmony_ci return -ENOMEM; 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci mutex_lock(&mdev->state_lock); 35178c2ecf20Sopenharmony_ci 35188c2ecf20Sopenharmony_ci memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); 35198c2ecf20Sopenharmony_ci memcpy(&new_prof.hwtstamp_config, &ts_config, sizeof(ts_config)); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); 35228c2ecf20Sopenharmony_ci if (err) 35238c2ecf20Sopenharmony_ci goto out; 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci if (priv->port_up) { 35268c2ecf20Sopenharmony_ci port_up = 1; 35278c2ecf20Sopenharmony_ci mlx4_en_stop_port(dev, 1); 35288c2ecf20Sopenharmony_ci } 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci mlx4_en_safe_replace_resources(priv, tmp); 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_ci if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX)) { 35338c2ecf20Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX) 35348c2ecf20Sopenharmony_ci dev->features |= NETIF_F_HW_VLAN_CTAG_RX; 35358c2ecf20Sopenharmony_ci else 35368c2ecf20Sopenharmony_ci dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; 35378c2ecf20Sopenharmony_ci } else if (ts_config.rx_filter == HWTSTAMP_FILTER_NONE) { 35388c2ecf20Sopenharmony_ci /* RX time-stamping is OFF, update the RX vlan offload 35398c2ecf20Sopenharmony_ci * to the latest wanted state 35408c2ecf20Sopenharmony_ci */ 35418c2ecf20Sopenharmony_ci if (dev->wanted_features & NETIF_F_HW_VLAN_CTAG_RX) 35428c2ecf20Sopenharmony_ci dev->features |= NETIF_F_HW_VLAN_CTAG_RX; 35438c2ecf20Sopenharmony_ci else 35448c2ecf20Sopenharmony_ci dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; 35458c2ecf20Sopenharmony_ci } 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_RXFCS)) { 35488c2ecf20Sopenharmony_ci if (features & NETIF_F_RXFCS) 35498c2ecf20Sopenharmony_ci dev->features |= NETIF_F_RXFCS; 35508c2ecf20Sopenharmony_ci else 35518c2ecf20Sopenharmony_ci dev->features &= ~NETIF_F_RXFCS; 35528c2ecf20Sopenharmony_ci } 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci /* RX vlan offload and RX time-stamping can't co-exist ! 35558c2ecf20Sopenharmony_ci * Regardless of the caller's choice, 35568c2ecf20Sopenharmony_ci * Turn Off RX vlan offload in case of time-stamping is ON 35578c2ecf20Sopenharmony_ci */ 35588c2ecf20Sopenharmony_ci if (ts_config.rx_filter != HWTSTAMP_FILTER_NONE) { 35598c2ecf20Sopenharmony_ci if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) 35608c2ecf20Sopenharmony_ci en_warn(priv, "Turning off RX vlan offload since RX time-stamping is ON\n"); 35618c2ecf20Sopenharmony_ci dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; 35628c2ecf20Sopenharmony_ci } 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ci if (port_up) { 35658c2ecf20Sopenharmony_ci err = mlx4_en_start_port(dev); 35668c2ecf20Sopenharmony_ci if (err) 35678c2ecf20Sopenharmony_ci en_err(priv, "Failed starting port\n"); 35688c2ecf20Sopenharmony_ci } 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci if (!err) 35718c2ecf20Sopenharmony_ci err = mlx4_en_moderation_update(priv); 35728c2ecf20Sopenharmony_ciout: 35738c2ecf20Sopenharmony_ci mutex_unlock(&mdev->state_lock); 35748c2ecf20Sopenharmony_ci kfree(tmp); 35758c2ecf20Sopenharmony_ci if (!err) 35768c2ecf20Sopenharmony_ci netdev_features_change(dev); 35778c2ecf20Sopenharmony_ci return err; 35788c2ecf20Sopenharmony_ci} 3579