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, &reg_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			     &params);
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			&notifier_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