162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2008-2010 Cisco Systems, Inc.  All rights reserved.
362306a36Sopenharmony_ci * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This program is free software; you may redistribute it and/or modify
662306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
762306a36Sopenharmony_ci * the Free Software Foundation; version 2 of the License.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1062306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1162306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1262306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
1362306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1462306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1562306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1662306a36Sopenharmony_ci * SOFTWARE.
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/module.h>
2162306a36Sopenharmony_ci#include <linux/kernel.h>
2262306a36Sopenharmony_ci#include <linux/string.h>
2362306a36Sopenharmony_ci#include <linux/errno.h>
2462306a36Sopenharmony_ci#include <linux/types.h>
2562306a36Sopenharmony_ci#include <linux/init.h>
2662306a36Sopenharmony_ci#include <linux/interrupt.h>
2762306a36Sopenharmony_ci#include <linux/workqueue.h>
2862306a36Sopenharmony_ci#include <linux/pci.h>
2962306a36Sopenharmony_ci#include <linux/netdevice.h>
3062306a36Sopenharmony_ci#include <linux/etherdevice.h>
3162306a36Sopenharmony_ci#include <linux/if.h>
3262306a36Sopenharmony_ci#include <linux/if_ether.h>
3362306a36Sopenharmony_ci#include <linux/if_vlan.h>
3462306a36Sopenharmony_ci#include <linux/in.h>
3562306a36Sopenharmony_ci#include <linux/ip.h>
3662306a36Sopenharmony_ci#include <linux/ipv6.h>
3762306a36Sopenharmony_ci#include <linux/tcp.h>
3862306a36Sopenharmony_ci#include <linux/rtnetlink.h>
3962306a36Sopenharmony_ci#include <linux/prefetch.h>
4062306a36Sopenharmony_ci#include <net/ip6_checksum.h>
4162306a36Sopenharmony_ci#include <linux/ktime.h>
4262306a36Sopenharmony_ci#include <linux/numa.h>
4362306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
4462306a36Sopenharmony_ci#include <linux/cpu_rmap.h>
4562306a36Sopenharmony_ci#endif
4662306a36Sopenharmony_ci#include <linux/crash_dump.h>
4762306a36Sopenharmony_ci#include <net/busy_poll.h>
4862306a36Sopenharmony_ci#include <net/vxlan.h>
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#include "cq_enet_desc.h"
5162306a36Sopenharmony_ci#include "vnic_dev.h"
5262306a36Sopenharmony_ci#include "vnic_intr.h"
5362306a36Sopenharmony_ci#include "vnic_stats.h"
5462306a36Sopenharmony_ci#include "vnic_vic.h"
5562306a36Sopenharmony_ci#include "enic_res.h"
5662306a36Sopenharmony_ci#include "enic.h"
5762306a36Sopenharmony_ci#include "enic_dev.h"
5862306a36Sopenharmony_ci#include "enic_pp.h"
5962306a36Sopenharmony_ci#include "enic_clsf.h"
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define ENIC_NOTIFY_TIMER_PERIOD	(2 * HZ)
6262306a36Sopenharmony_ci#define WQ_ENET_MAX_DESC_LEN		(1 << WQ_ENET_LEN_BITS)
6362306a36Sopenharmony_ci#define MAX_TSO				(1 << 16)
6462306a36Sopenharmony_ci#define ENIC_DESC_MAX_SPLITS		(MAX_TSO / WQ_ENET_MAX_DESC_LEN + 1)
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define PCI_DEVICE_ID_CISCO_VIC_ENET         0x0043  /* ethernet vnic */
6762306a36Sopenharmony_ci#define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN     0x0044  /* enet dynamic vnic */
6862306a36Sopenharmony_ci#define PCI_DEVICE_ID_CISCO_VIC_ENET_VF      0x0071  /* enet SRIOV VF */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#define RX_COPYBREAK_DEFAULT		256
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* Supported devices */
7362306a36Sopenharmony_cistatic const struct pci_device_id enic_id_table[] = {
7462306a36Sopenharmony_ci	{ PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) },
7562306a36Sopenharmony_ci	{ PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) },
7662306a36Sopenharmony_ci	{ PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_VF) },
7762306a36Sopenharmony_ci	{ 0, }	/* end of table */
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESCRIPTION);
8162306a36Sopenharmony_ciMODULE_AUTHOR("Scott Feldman <scofeldm@cisco.com>");
8262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
8362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, enic_id_table);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define ENIC_LARGE_PKT_THRESHOLD		1000
8662306a36Sopenharmony_ci#define ENIC_MAX_COALESCE_TIMERS		10
8762306a36Sopenharmony_ci/*  Interrupt moderation table, which will be used to decide the
8862306a36Sopenharmony_ci *  coalescing timer values
8962306a36Sopenharmony_ci *  {rx_rate in Mbps, mapping percentage of the range}
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_cistatic struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = {
9262306a36Sopenharmony_ci	{4000,  0},
9362306a36Sopenharmony_ci	{4400, 10},
9462306a36Sopenharmony_ci	{5060, 20},
9562306a36Sopenharmony_ci	{5230, 30},
9662306a36Sopenharmony_ci	{5540, 40},
9762306a36Sopenharmony_ci	{5820, 50},
9862306a36Sopenharmony_ci	{6120, 60},
9962306a36Sopenharmony_ci	{6435, 70},
10062306a36Sopenharmony_ci	{6745, 80},
10162306a36Sopenharmony_ci	{7000, 90},
10262306a36Sopenharmony_ci	{0xFFFFFFFF, 100}
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* This table helps the driver to pick different ranges for rx coalescing
10662306a36Sopenharmony_ci * timer depending on the link speed.
10762306a36Sopenharmony_ci */
10862306a36Sopenharmony_cistatic struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = {
10962306a36Sopenharmony_ci	{0,  0}, /* 0  - 4  Gbps */
11062306a36Sopenharmony_ci	{0,  3}, /* 4  - 10 Gbps */
11162306a36Sopenharmony_ci	{3,  6}, /* 10 - 40 Gbps */
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void enic_init_affinity_hint(struct enic *enic)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	int numa_node = dev_to_node(&enic->pdev->dev);
11762306a36Sopenharmony_ci	int i;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	for (i = 0; i < enic->intr_count; i++) {
12062306a36Sopenharmony_ci		if (enic_is_err_intr(enic, i) || enic_is_notify_intr(enic, i) ||
12162306a36Sopenharmony_ci		    (cpumask_available(enic->msix[i].affinity_mask) &&
12262306a36Sopenharmony_ci		     !cpumask_empty(enic->msix[i].affinity_mask)))
12362306a36Sopenharmony_ci			continue;
12462306a36Sopenharmony_ci		if (zalloc_cpumask_var(&enic->msix[i].affinity_mask,
12562306a36Sopenharmony_ci				       GFP_KERNEL))
12662306a36Sopenharmony_ci			cpumask_set_cpu(cpumask_local_spread(i, numa_node),
12762306a36Sopenharmony_ci					enic->msix[i].affinity_mask);
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic void enic_free_affinity_hint(struct enic *enic)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	int i;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	for (i = 0; i < enic->intr_count; i++) {
13662306a36Sopenharmony_ci		if (enic_is_err_intr(enic, i) || enic_is_notify_intr(enic, i))
13762306a36Sopenharmony_ci			continue;
13862306a36Sopenharmony_ci		free_cpumask_var(enic->msix[i].affinity_mask);
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic void enic_set_affinity_hint(struct enic *enic)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	int i;
14562306a36Sopenharmony_ci	int err;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	for (i = 0; i < enic->intr_count; i++) {
14862306a36Sopenharmony_ci		if (enic_is_err_intr(enic, i)		||
14962306a36Sopenharmony_ci		    enic_is_notify_intr(enic, i)	||
15062306a36Sopenharmony_ci		    !cpumask_available(enic->msix[i].affinity_mask) ||
15162306a36Sopenharmony_ci		    cpumask_empty(enic->msix[i].affinity_mask))
15262306a36Sopenharmony_ci			continue;
15362306a36Sopenharmony_ci		err = irq_update_affinity_hint(enic->msix_entry[i].vector,
15462306a36Sopenharmony_ci					       enic->msix[i].affinity_mask);
15562306a36Sopenharmony_ci		if (err)
15662306a36Sopenharmony_ci			netdev_warn(enic->netdev, "irq_update_affinity_hint failed, err %d\n",
15762306a36Sopenharmony_ci				    err);
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	for (i = 0; i < enic->wq_count; i++) {
16162306a36Sopenharmony_ci		int wq_intr = enic_msix_wq_intr(enic, i);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci		if (cpumask_available(enic->msix[wq_intr].affinity_mask) &&
16462306a36Sopenharmony_ci		    !cpumask_empty(enic->msix[wq_intr].affinity_mask))
16562306a36Sopenharmony_ci			netif_set_xps_queue(enic->netdev,
16662306a36Sopenharmony_ci					    enic->msix[wq_intr].affinity_mask,
16762306a36Sopenharmony_ci					    i);
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic void enic_unset_affinity_hint(struct enic *enic)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int i;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	for (i = 0; i < enic->intr_count; i++)
17662306a36Sopenharmony_ci		irq_update_affinity_hint(enic->msix_entry[i].vector, NULL);
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int enic_udp_tunnel_set_port(struct net_device *netdev,
18062306a36Sopenharmony_ci				    unsigned int table, unsigned int entry,
18162306a36Sopenharmony_ci				    struct udp_tunnel_info *ti)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
18462306a36Sopenharmony_ci	int err;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	spin_lock_bh(&enic->devcmd_lock);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	err = vnic_dev_overlay_offload_cfg(enic->vdev,
18962306a36Sopenharmony_ci					   OVERLAY_CFG_VXLAN_PORT_UPDATE,
19062306a36Sopenharmony_ci					   ntohs(ti->port));
19162306a36Sopenharmony_ci	if (err)
19262306a36Sopenharmony_ci		goto error;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	err = vnic_dev_overlay_offload_ctrl(enic->vdev, OVERLAY_FEATURE_VXLAN,
19562306a36Sopenharmony_ci					    enic->vxlan.patch_level);
19662306a36Sopenharmony_ci	if (err)
19762306a36Sopenharmony_ci		goto error;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	enic->vxlan.vxlan_udp_port_number = ntohs(ti->port);
20062306a36Sopenharmony_cierror:
20162306a36Sopenharmony_ci	spin_unlock_bh(&enic->devcmd_lock);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	return err;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic int enic_udp_tunnel_unset_port(struct net_device *netdev,
20762306a36Sopenharmony_ci				      unsigned int table, unsigned int entry,
20862306a36Sopenharmony_ci				      struct udp_tunnel_info *ti)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
21162306a36Sopenharmony_ci	int err;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	spin_lock_bh(&enic->devcmd_lock);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	err = vnic_dev_overlay_offload_ctrl(enic->vdev, OVERLAY_FEATURE_VXLAN,
21662306a36Sopenharmony_ci					    OVERLAY_OFFLOAD_DISABLE);
21762306a36Sopenharmony_ci	if (err)
21862306a36Sopenharmony_ci		goto unlock;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	enic->vxlan.vxlan_udp_port_number = 0;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ciunlock:
22362306a36Sopenharmony_ci	spin_unlock_bh(&enic->devcmd_lock);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return err;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic const struct udp_tunnel_nic_info enic_udp_tunnels = {
22962306a36Sopenharmony_ci	.set_port	= enic_udp_tunnel_set_port,
23062306a36Sopenharmony_ci	.unset_port	= enic_udp_tunnel_unset_port,
23162306a36Sopenharmony_ci	.tables		= {
23262306a36Sopenharmony_ci		{ .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, },
23362306a36Sopenharmony_ci	},
23462306a36Sopenharmony_ci}, enic_udp_tunnels_v4 = {
23562306a36Sopenharmony_ci	.set_port	= enic_udp_tunnel_set_port,
23662306a36Sopenharmony_ci	.unset_port	= enic_udp_tunnel_unset_port,
23762306a36Sopenharmony_ci	.flags		= UDP_TUNNEL_NIC_INFO_IPV4_ONLY,
23862306a36Sopenharmony_ci	.tables		= {
23962306a36Sopenharmony_ci		{ .n_entries = 1, .tunnel_types = UDP_TUNNEL_TYPE_VXLAN, },
24062306a36Sopenharmony_ci	},
24162306a36Sopenharmony_ci};
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic netdev_features_t enic_features_check(struct sk_buff *skb,
24462306a36Sopenharmony_ci					     struct net_device *dev,
24562306a36Sopenharmony_ci					     netdev_features_t features)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	const struct ethhdr *eth = (struct ethhdr *)skb_inner_mac_header(skb);
24862306a36Sopenharmony_ci	struct enic *enic = netdev_priv(dev);
24962306a36Sopenharmony_ci	struct udphdr *udph;
25062306a36Sopenharmony_ci	u16 port = 0;
25162306a36Sopenharmony_ci	u8 proto;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (!skb->encapsulation)
25462306a36Sopenharmony_ci		return features;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	features = vxlan_features_check(skb, features);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	switch (vlan_get_protocol(skb)) {
25962306a36Sopenharmony_ci	case htons(ETH_P_IPV6):
26062306a36Sopenharmony_ci		if (!(enic->vxlan.flags & ENIC_VXLAN_OUTER_IPV6))
26162306a36Sopenharmony_ci			goto out;
26262306a36Sopenharmony_ci		proto = ipv6_hdr(skb)->nexthdr;
26362306a36Sopenharmony_ci		break;
26462306a36Sopenharmony_ci	case htons(ETH_P_IP):
26562306a36Sopenharmony_ci		proto = ip_hdr(skb)->protocol;
26662306a36Sopenharmony_ci		break;
26762306a36Sopenharmony_ci	default:
26862306a36Sopenharmony_ci		goto out;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	switch (eth->h_proto) {
27262306a36Sopenharmony_ci	case ntohs(ETH_P_IPV6):
27362306a36Sopenharmony_ci		if (!(enic->vxlan.flags & ENIC_VXLAN_INNER_IPV6))
27462306a36Sopenharmony_ci			goto out;
27562306a36Sopenharmony_ci		fallthrough;
27662306a36Sopenharmony_ci	case ntohs(ETH_P_IP):
27762306a36Sopenharmony_ci		break;
27862306a36Sopenharmony_ci	default:
27962306a36Sopenharmony_ci		goto out;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (proto == IPPROTO_UDP) {
28462306a36Sopenharmony_ci		udph = udp_hdr(skb);
28562306a36Sopenharmony_ci		port = be16_to_cpu(udph->dest);
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* HW supports offload of only one UDP port. Remove CSUM and GSO MASK
28962306a36Sopenharmony_ci	 * for other UDP port tunnels
29062306a36Sopenharmony_ci	 */
29162306a36Sopenharmony_ci	if (port  != enic->vxlan.vxlan_udp_port_number)
29262306a36Sopenharmony_ci		goto out;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return features;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ciout:
29762306a36Sopenharmony_ci	return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ciint enic_is_dynamic(struct enic *enic)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ciint enic_sriov_enabled(struct enic *enic)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	return (enic->priv_flags & ENIC_SRIOV_ENABLED) ? 1 : 0;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic int enic_is_sriov_vf(struct enic *enic)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_VF;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ciint enic_is_valid_vf(struct enic *enic, int vf)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
31862306a36Sopenharmony_ci	return vf >= 0 && vf < enic->num_vfs;
31962306a36Sopenharmony_ci#else
32062306a36Sopenharmony_ci	return 0;
32162306a36Sopenharmony_ci#endif
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct enic *enic = vnic_dev_priv(wq->vdev);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (buf->sop)
32962306a36Sopenharmony_ci		dma_unmap_single(&enic->pdev->dev, buf->dma_addr, buf->len,
33062306a36Sopenharmony_ci				 DMA_TO_DEVICE);
33162306a36Sopenharmony_ci	else
33262306a36Sopenharmony_ci		dma_unmap_page(&enic->pdev->dev, buf->dma_addr, buf->len,
33362306a36Sopenharmony_ci			       DMA_TO_DEVICE);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (buf->os_buf)
33662306a36Sopenharmony_ci		dev_kfree_skb_any(buf->os_buf);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic void enic_wq_free_buf(struct vnic_wq *wq,
34062306a36Sopenharmony_ci	struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	enic_free_wq_buf(wq, buf);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic int enic_wq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
34662306a36Sopenharmony_ci	u8 type, u16 q_number, u16 completed_index, void *opaque)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct enic *enic = vnic_dev_priv(vdev);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	spin_lock(&enic->wq_lock[q_number]);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	vnic_wq_service(&enic->wq[q_number], cq_desc,
35362306a36Sopenharmony_ci		completed_index, enic_wq_free_buf,
35462306a36Sopenharmony_ci		opaque);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (netif_tx_queue_stopped(netdev_get_tx_queue(enic->netdev, q_number)) &&
35762306a36Sopenharmony_ci	    vnic_wq_desc_avail(&enic->wq[q_number]) >=
35862306a36Sopenharmony_ci	    (MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS))
35962306a36Sopenharmony_ci		netif_wake_subqueue(enic->netdev, q_number);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	spin_unlock(&enic->wq_lock[q_number]);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return 0;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic bool enic_log_q_error(struct enic *enic)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	unsigned int i;
36962306a36Sopenharmony_ci	u32 error_status;
37062306a36Sopenharmony_ci	bool err = false;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	for (i = 0; i < enic->wq_count; i++) {
37362306a36Sopenharmony_ci		error_status = vnic_wq_error_status(&enic->wq[i]);
37462306a36Sopenharmony_ci		err |= error_status;
37562306a36Sopenharmony_ci		if (error_status)
37662306a36Sopenharmony_ci			netdev_err(enic->netdev, "WQ[%d] error_status %d\n",
37762306a36Sopenharmony_ci				i, error_status);
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	for (i = 0; i < enic->rq_count; i++) {
38162306a36Sopenharmony_ci		error_status = vnic_rq_error_status(&enic->rq[i]);
38262306a36Sopenharmony_ci		err |= error_status;
38362306a36Sopenharmony_ci		if (error_status)
38462306a36Sopenharmony_ci			netdev_err(enic->netdev, "RQ[%d] error_status %d\n",
38562306a36Sopenharmony_ci				i, error_status);
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	return err;
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic void enic_msglvl_check(struct enic *enic)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	u32 msg_enable = vnic_dev_msg_lvl(enic->vdev);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (msg_enable != enic->msg_enable) {
39662306a36Sopenharmony_ci		netdev_info(enic->netdev, "msg lvl changed from 0x%x to 0x%x\n",
39762306a36Sopenharmony_ci			enic->msg_enable, msg_enable);
39862306a36Sopenharmony_ci		enic->msg_enable = msg_enable;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic void enic_mtu_check(struct enic *enic)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	u32 mtu = vnic_dev_mtu(enic->vdev);
40562306a36Sopenharmony_ci	struct net_device *netdev = enic->netdev;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (mtu && mtu != enic->port_mtu) {
40862306a36Sopenharmony_ci		enic->port_mtu = mtu;
40962306a36Sopenharmony_ci		if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) {
41062306a36Sopenharmony_ci			mtu = max_t(int, ENIC_MIN_MTU,
41162306a36Sopenharmony_ci				min_t(int, ENIC_MAX_MTU, mtu));
41262306a36Sopenharmony_ci			if (mtu != netdev->mtu)
41362306a36Sopenharmony_ci				schedule_work(&enic->change_mtu_work);
41462306a36Sopenharmony_ci		} else {
41562306a36Sopenharmony_ci			if (mtu < netdev->mtu)
41662306a36Sopenharmony_ci				netdev_warn(netdev,
41762306a36Sopenharmony_ci					"interface MTU (%d) set higher "
41862306a36Sopenharmony_ci					"than switch port MTU (%d)\n",
41962306a36Sopenharmony_ci					netdev->mtu, mtu);
42062306a36Sopenharmony_ci		}
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic void enic_link_check(struct enic *enic)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	int link_status = vnic_dev_link_status(enic->vdev);
42762306a36Sopenharmony_ci	int carrier_ok = netif_carrier_ok(enic->netdev);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (link_status && !carrier_ok) {
43062306a36Sopenharmony_ci		netdev_info(enic->netdev, "Link UP\n");
43162306a36Sopenharmony_ci		netif_carrier_on(enic->netdev);
43262306a36Sopenharmony_ci	} else if (!link_status && carrier_ok) {
43362306a36Sopenharmony_ci		netdev_info(enic->netdev, "Link DOWN\n");
43462306a36Sopenharmony_ci		netif_carrier_off(enic->netdev);
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic void enic_notify_check(struct enic *enic)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	enic_msglvl_check(enic);
44162306a36Sopenharmony_ci	enic_mtu_check(enic);
44262306a36Sopenharmony_ci	enic_link_check(enic);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci#define ENIC_TEST_INTR(pba, i) (pba & (1 << i))
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic irqreturn_t enic_isr_legacy(int irq, void *data)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct net_device *netdev = data;
45062306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
45162306a36Sopenharmony_ci	unsigned int io_intr = ENIC_LEGACY_IO_INTR;
45262306a36Sopenharmony_ci	unsigned int err_intr = ENIC_LEGACY_ERR_INTR;
45362306a36Sopenharmony_ci	unsigned int notify_intr = ENIC_LEGACY_NOTIFY_INTR;
45462306a36Sopenharmony_ci	u32 pba;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	vnic_intr_mask(&enic->intr[io_intr]);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	pba = vnic_intr_legacy_pba(enic->legacy_pba);
45962306a36Sopenharmony_ci	if (!pba) {
46062306a36Sopenharmony_ci		vnic_intr_unmask(&enic->intr[io_intr]);
46162306a36Sopenharmony_ci		return IRQ_NONE;	/* not our interrupt */
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (ENIC_TEST_INTR(pba, notify_intr)) {
46562306a36Sopenharmony_ci		enic_notify_check(enic);
46662306a36Sopenharmony_ci		vnic_intr_return_all_credits(&enic->intr[notify_intr]);
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (ENIC_TEST_INTR(pba, err_intr)) {
47062306a36Sopenharmony_ci		vnic_intr_return_all_credits(&enic->intr[err_intr]);
47162306a36Sopenharmony_ci		enic_log_q_error(enic);
47262306a36Sopenharmony_ci		/* schedule recovery from WQ/RQ error */
47362306a36Sopenharmony_ci		schedule_work(&enic->reset);
47462306a36Sopenharmony_ci		return IRQ_HANDLED;
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (ENIC_TEST_INTR(pba, io_intr))
47862306a36Sopenharmony_ci		napi_schedule_irqoff(&enic->napi[0]);
47962306a36Sopenharmony_ci	else
48062306a36Sopenharmony_ci		vnic_intr_unmask(&enic->intr[io_intr]);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	return IRQ_HANDLED;
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_cistatic irqreturn_t enic_isr_msi(int irq, void *data)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct enic *enic = data;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* With MSI, there is no sharing of interrupts, so this is
49062306a36Sopenharmony_ci	 * our interrupt and there is no need to ack it.  The device
49162306a36Sopenharmony_ci	 * is not providing per-vector masking, so the OS will not
49262306a36Sopenharmony_ci	 * write to PCI config space to mask/unmask the interrupt.
49362306a36Sopenharmony_ci	 * We're using mask_on_assertion for MSI, so the device
49462306a36Sopenharmony_ci	 * automatically masks the interrupt when the interrupt is
49562306a36Sopenharmony_ci	 * generated.  Later, when exiting polling, the interrupt
49662306a36Sopenharmony_ci	 * will be unmasked (see enic_poll).
49762306a36Sopenharmony_ci	 *
49862306a36Sopenharmony_ci	 * Also, the device uses the same PCIe Traffic Class (TC)
49962306a36Sopenharmony_ci	 * for Memory Write data and MSI, so there are no ordering
50062306a36Sopenharmony_ci	 * issues; the MSI will always arrive at the Root Complex
50162306a36Sopenharmony_ci	 * _after_ corresponding Memory Writes (i.e. descriptor
50262306a36Sopenharmony_ci	 * writes).
50362306a36Sopenharmony_ci	 */
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	napi_schedule_irqoff(&enic->napi[0]);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	return IRQ_HANDLED;
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic irqreturn_t enic_isr_msix(int irq, void *data)
51162306a36Sopenharmony_ci{
51262306a36Sopenharmony_ci	struct napi_struct *napi = data;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	napi_schedule_irqoff(napi);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	return IRQ_HANDLED;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic irqreturn_t enic_isr_msix_err(int irq, void *data)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	struct enic *enic = data;
52262306a36Sopenharmony_ci	unsigned int intr = enic_msix_err_intr(enic);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	vnic_intr_return_all_credits(&enic->intr[intr]);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (enic_log_q_error(enic))
52762306a36Sopenharmony_ci		/* schedule recovery from WQ/RQ error */
52862306a36Sopenharmony_ci		schedule_work(&enic->reset);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return IRQ_HANDLED;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic irqreturn_t enic_isr_msix_notify(int irq, void *data)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	struct enic *enic = data;
53662306a36Sopenharmony_ci	unsigned int intr = enic_msix_notify_intr(enic);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	enic_notify_check(enic);
53962306a36Sopenharmony_ci	vnic_intr_return_all_credits(&enic->intr[intr]);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	return IRQ_HANDLED;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic int enic_queue_wq_skb_cont(struct enic *enic, struct vnic_wq *wq,
54562306a36Sopenharmony_ci				  struct sk_buff *skb, unsigned int len_left,
54662306a36Sopenharmony_ci				  int loopback)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	const skb_frag_t *frag;
54962306a36Sopenharmony_ci	dma_addr_t dma_addr;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* Queue additional data fragments */
55262306a36Sopenharmony_ci	for (frag = skb_shinfo(skb)->frags; len_left; frag++) {
55362306a36Sopenharmony_ci		len_left -= skb_frag_size(frag);
55462306a36Sopenharmony_ci		dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag, 0,
55562306a36Sopenharmony_ci					    skb_frag_size(frag),
55662306a36Sopenharmony_ci					    DMA_TO_DEVICE);
55762306a36Sopenharmony_ci		if (unlikely(enic_dma_map_check(enic, dma_addr)))
55862306a36Sopenharmony_ci			return -ENOMEM;
55962306a36Sopenharmony_ci		enic_queue_wq_desc_cont(wq, skb, dma_addr, skb_frag_size(frag),
56062306a36Sopenharmony_ci					(len_left == 0),	/* EOP? */
56162306a36Sopenharmony_ci					loopback);
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	return 0;
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic int enic_queue_wq_skb_vlan(struct enic *enic, struct vnic_wq *wq,
56862306a36Sopenharmony_ci				  struct sk_buff *skb, int vlan_tag_insert,
56962306a36Sopenharmony_ci				  unsigned int vlan_tag, int loopback)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	unsigned int head_len = skb_headlen(skb);
57262306a36Sopenharmony_ci	unsigned int len_left = skb->len - head_len;
57362306a36Sopenharmony_ci	int eop = (len_left == 0);
57462306a36Sopenharmony_ci	dma_addr_t dma_addr;
57562306a36Sopenharmony_ci	int err = 0;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	dma_addr = dma_map_single(&enic->pdev->dev, skb->data, head_len,
57862306a36Sopenharmony_ci				  DMA_TO_DEVICE);
57962306a36Sopenharmony_ci	if (unlikely(enic_dma_map_check(enic, dma_addr)))
58062306a36Sopenharmony_ci		return -ENOMEM;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* Queue the main skb fragment. The fragments are no larger
58362306a36Sopenharmony_ci	 * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less
58462306a36Sopenharmony_ci	 * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor
58562306a36Sopenharmony_ci	 * per fragment is queued.
58662306a36Sopenharmony_ci	 */
58762306a36Sopenharmony_ci	enic_queue_wq_desc(wq, skb, dma_addr, head_len,	vlan_tag_insert,
58862306a36Sopenharmony_ci			   vlan_tag, eop, loopback);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	if (!eop)
59162306a36Sopenharmony_ci		err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	return err;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic int enic_queue_wq_skb_csum_l4(struct enic *enic, struct vnic_wq *wq,
59762306a36Sopenharmony_ci				     struct sk_buff *skb, int vlan_tag_insert,
59862306a36Sopenharmony_ci				     unsigned int vlan_tag, int loopback)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	unsigned int head_len = skb_headlen(skb);
60162306a36Sopenharmony_ci	unsigned int len_left = skb->len - head_len;
60262306a36Sopenharmony_ci	unsigned int hdr_len = skb_checksum_start_offset(skb);
60362306a36Sopenharmony_ci	unsigned int csum_offset = hdr_len + skb->csum_offset;
60462306a36Sopenharmony_ci	int eop = (len_left == 0);
60562306a36Sopenharmony_ci	dma_addr_t dma_addr;
60662306a36Sopenharmony_ci	int err = 0;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	dma_addr = dma_map_single(&enic->pdev->dev, skb->data, head_len,
60962306a36Sopenharmony_ci				  DMA_TO_DEVICE);
61062306a36Sopenharmony_ci	if (unlikely(enic_dma_map_check(enic, dma_addr)))
61162306a36Sopenharmony_ci		return -ENOMEM;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* Queue the main skb fragment. The fragments are no larger
61462306a36Sopenharmony_ci	 * than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less
61562306a36Sopenharmony_ci	 * than WQ_ENET_MAX_DESC_LEN length. So only one descriptor
61662306a36Sopenharmony_ci	 * per fragment is queued.
61762306a36Sopenharmony_ci	 */
61862306a36Sopenharmony_ci	enic_queue_wq_desc_csum_l4(wq, skb, dma_addr, head_len,	csum_offset,
61962306a36Sopenharmony_ci				   hdr_len, vlan_tag_insert, vlan_tag, eop,
62062306a36Sopenharmony_ci				   loopback);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (!eop)
62362306a36Sopenharmony_ci		err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	return err;
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic void enic_preload_tcp_csum_encap(struct sk_buff *skb)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	const struct ethhdr *eth = (struct ethhdr *)skb_inner_mac_header(skb);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	switch (eth->h_proto) {
63362306a36Sopenharmony_ci	case ntohs(ETH_P_IP):
63462306a36Sopenharmony_ci		inner_ip_hdr(skb)->check = 0;
63562306a36Sopenharmony_ci		inner_tcp_hdr(skb)->check =
63662306a36Sopenharmony_ci			~csum_tcpudp_magic(inner_ip_hdr(skb)->saddr,
63762306a36Sopenharmony_ci					   inner_ip_hdr(skb)->daddr, 0,
63862306a36Sopenharmony_ci					   IPPROTO_TCP, 0);
63962306a36Sopenharmony_ci		break;
64062306a36Sopenharmony_ci	case ntohs(ETH_P_IPV6):
64162306a36Sopenharmony_ci		inner_tcp_hdr(skb)->check =
64262306a36Sopenharmony_ci			~csum_ipv6_magic(&inner_ipv6_hdr(skb)->saddr,
64362306a36Sopenharmony_ci					 &inner_ipv6_hdr(skb)->daddr, 0,
64462306a36Sopenharmony_ci					 IPPROTO_TCP, 0);
64562306a36Sopenharmony_ci		break;
64662306a36Sopenharmony_ci	default:
64762306a36Sopenharmony_ci		WARN_ONCE(1, "Non ipv4/ipv6 inner pkt for encap offload");
64862306a36Sopenharmony_ci		break;
64962306a36Sopenharmony_ci	}
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic void enic_preload_tcp_csum(struct sk_buff *skb)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	/* Preload TCP csum field with IP pseudo hdr calculated
65562306a36Sopenharmony_ci	 * with IP length set to zero.  HW will later add in length
65662306a36Sopenharmony_ci	 * to each TCP segment resulting from the TSO.
65762306a36Sopenharmony_ci	 */
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	if (skb->protocol == cpu_to_be16(ETH_P_IP)) {
66062306a36Sopenharmony_ci		ip_hdr(skb)->check = 0;
66162306a36Sopenharmony_ci		tcp_hdr(skb)->check = ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
66262306a36Sopenharmony_ci			ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0);
66362306a36Sopenharmony_ci	} else if (skb->protocol == cpu_to_be16(ETH_P_IPV6)) {
66462306a36Sopenharmony_ci		tcp_v6_gso_csum_prep(skb);
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq,
66962306a36Sopenharmony_ci				 struct sk_buff *skb, unsigned int mss,
67062306a36Sopenharmony_ci				 int vlan_tag_insert, unsigned int vlan_tag,
67162306a36Sopenharmony_ci				 int loopback)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	unsigned int frag_len_left = skb_headlen(skb);
67462306a36Sopenharmony_ci	unsigned int len_left = skb->len - frag_len_left;
67562306a36Sopenharmony_ci	int eop = (len_left == 0);
67662306a36Sopenharmony_ci	unsigned int offset = 0;
67762306a36Sopenharmony_ci	unsigned int hdr_len;
67862306a36Sopenharmony_ci	dma_addr_t dma_addr;
67962306a36Sopenharmony_ci	unsigned int len;
68062306a36Sopenharmony_ci	skb_frag_t *frag;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	if (skb->encapsulation) {
68362306a36Sopenharmony_ci		hdr_len = skb_inner_tcp_all_headers(skb);
68462306a36Sopenharmony_ci		enic_preload_tcp_csum_encap(skb);
68562306a36Sopenharmony_ci	} else {
68662306a36Sopenharmony_ci		hdr_len = skb_tcp_all_headers(skb);
68762306a36Sopenharmony_ci		enic_preload_tcp_csum(skb);
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	/* Queue WQ_ENET_MAX_DESC_LEN length descriptors
69162306a36Sopenharmony_ci	 * for the main skb fragment
69262306a36Sopenharmony_ci	 */
69362306a36Sopenharmony_ci	while (frag_len_left) {
69462306a36Sopenharmony_ci		len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN);
69562306a36Sopenharmony_ci		dma_addr = dma_map_single(&enic->pdev->dev,
69662306a36Sopenharmony_ci					  skb->data + offset, len,
69762306a36Sopenharmony_ci					  DMA_TO_DEVICE);
69862306a36Sopenharmony_ci		if (unlikely(enic_dma_map_check(enic, dma_addr)))
69962306a36Sopenharmony_ci			return -ENOMEM;
70062306a36Sopenharmony_ci		enic_queue_wq_desc_tso(wq, skb, dma_addr, len, mss, hdr_len,
70162306a36Sopenharmony_ci				       vlan_tag_insert, vlan_tag,
70262306a36Sopenharmony_ci				       eop && (len == frag_len_left), loopback);
70362306a36Sopenharmony_ci		frag_len_left -= len;
70462306a36Sopenharmony_ci		offset += len;
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	if (eop)
70862306a36Sopenharmony_ci		return 0;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	/* Queue WQ_ENET_MAX_DESC_LEN length descriptors
71162306a36Sopenharmony_ci	 * for additional data fragments
71262306a36Sopenharmony_ci	 */
71362306a36Sopenharmony_ci	for (frag = skb_shinfo(skb)->frags; len_left; frag++) {
71462306a36Sopenharmony_ci		len_left -= skb_frag_size(frag);
71562306a36Sopenharmony_ci		frag_len_left = skb_frag_size(frag);
71662306a36Sopenharmony_ci		offset = 0;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci		while (frag_len_left) {
71962306a36Sopenharmony_ci			len = min(frag_len_left,
72062306a36Sopenharmony_ci				(unsigned int)WQ_ENET_MAX_DESC_LEN);
72162306a36Sopenharmony_ci			dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag,
72262306a36Sopenharmony_ci						    offset, len,
72362306a36Sopenharmony_ci						    DMA_TO_DEVICE);
72462306a36Sopenharmony_ci			if (unlikely(enic_dma_map_check(enic, dma_addr)))
72562306a36Sopenharmony_ci				return -ENOMEM;
72662306a36Sopenharmony_ci			enic_queue_wq_desc_cont(wq, skb, dma_addr, len,
72762306a36Sopenharmony_ci						(len_left == 0) &&
72862306a36Sopenharmony_ci						 (len == frag_len_left),/*EOP*/
72962306a36Sopenharmony_ci						loopback);
73062306a36Sopenharmony_ci			frag_len_left -= len;
73162306a36Sopenharmony_ci			offset += len;
73262306a36Sopenharmony_ci		}
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	return 0;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic inline int enic_queue_wq_skb_encap(struct enic *enic, struct vnic_wq *wq,
73962306a36Sopenharmony_ci					  struct sk_buff *skb,
74062306a36Sopenharmony_ci					  int vlan_tag_insert,
74162306a36Sopenharmony_ci					  unsigned int vlan_tag, int loopback)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	unsigned int head_len = skb_headlen(skb);
74462306a36Sopenharmony_ci	unsigned int len_left = skb->len - head_len;
74562306a36Sopenharmony_ci	/* Hardware will overwrite the checksum fields, calculating from
74662306a36Sopenharmony_ci	 * scratch and ignoring the value placed by software.
74762306a36Sopenharmony_ci	 * Offload mode = 00
74862306a36Sopenharmony_ci	 * mss[2], mss[1], mss[0] bits are set
74962306a36Sopenharmony_ci	 */
75062306a36Sopenharmony_ci	unsigned int mss_or_csum = 7;
75162306a36Sopenharmony_ci	int eop = (len_left == 0);
75262306a36Sopenharmony_ci	dma_addr_t dma_addr;
75362306a36Sopenharmony_ci	int err = 0;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	dma_addr = dma_map_single(&enic->pdev->dev, skb->data, head_len,
75662306a36Sopenharmony_ci				  DMA_TO_DEVICE);
75762306a36Sopenharmony_ci	if (unlikely(enic_dma_map_check(enic, dma_addr)))
75862306a36Sopenharmony_ci		return -ENOMEM;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	enic_queue_wq_desc_ex(wq, skb, dma_addr, head_len, mss_or_csum, 0,
76162306a36Sopenharmony_ci			      vlan_tag_insert, vlan_tag,
76262306a36Sopenharmony_ci			      WQ_ENET_OFFLOAD_MODE_CSUM, eop, 1 /* SOP */, eop,
76362306a36Sopenharmony_ci			      loopback);
76462306a36Sopenharmony_ci	if (!eop)
76562306a36Sopenharmony_ci		err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	return err;
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_cistatic inline int enic_queue_wq_skb(struct enic *enic,
77162306a36Sopenharmony_ci	struct vnic_wq *wq, struct sk_buff *skb)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	unsigned int mss = skb_shinfo(skb)->gso_size;
77462306a36Sopenharmony_ci	unsigned int vlan_tag = 0;
77562306a36Sopenharmony_ci	int vlan_tag_insert = 0;
77662306a36Sopenharmony_ci	int loopback = 0;
77762306a36Sopenharmony_ci	int err;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (skb_vlan_tag_present(skb)) {
78062306a36Sopenharmony_ci		/* VLAN tag from trunking driver */
78162306a36Sopenharmony_ci		vlan_tag_insert = 1;
78262306a36Sopenharmony_ci		vlan_tag = skb_vlan_tag_get(skb);
78362306a36Sopenharmony_ci	} else if (enic->loop_enable) {
78462306a36Sopenharmony_ci		vlan_tag = enic->loop_tag;
78562306a36Sopenharmony_ci		loopback = 1;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (mss)
78962306a36Sopenharmony_ci		err = enic_queue_wq_skb_tso(enic, wq, skb, mss,
79062306a36Sopenharmony_ci					    vlan_tag_insert, vlan_tag,
79162306a36Sopenharmony_ci					    loopback);
79262306a36Sopenharmony_ci	else if (skb->encapsulation)
79362306a36Sopenharmony_ci		err = enic_queue_wq_skb_encap(enic, wq, skb, vlan_tag_insert,
79462306a36Sopenharmony_ci					      vlan_tag, loopback);
79562306a36Sopenharmony_ci	else if	(skb->ip_summed == CHECKSUM_PARTIAL)
79662306a36Sopenharmony_ci		err = enic_queue_wq_skb_csum_l4(enic, wq, skb, vlan_tag_insert,
79762306a36Sopenharmony_ci						vlan_tag, loopback);
79862306a36Sopenharmony_ci	else
79962306a36Sopenharmony_ci		err = enic_queue_wq_skb_vlan(enic, wq, skb, vlan_tag_insert,
80062306a36Sopenharmony_ci					     vlan_tag, loopback);
80162306a36Sopenharmony_ci	if (unlikely(err)) {
80262306a36Sopenharmony_ci		struct vnic_wq_buf *buf;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		buf = wq->to_use->prev;
80562306a36Sopenharmony_ci		/* while not EOP of previous pkt && queue not empty.
80662306a36Sopenharmony_ci		 * For all non EOP bufs, os_buf is NULL.
80762306a36Sopenharmony_ci		 */
80862306a36Sopenharmony_ci		while (!buf->os_buf && (buf->next != wq->to_clean)) {
80962306a36Sopenharmony_ci			enic_free_wq_buf(wq, buf);
81062306a36Sopenharmony_ci			wq->ring.desc_avail++;
81162306a36Sopenharmony_ci			buf = buf->prev;
81262306a36Sopenharmony_ci		}
81362306a36Sopenharmony_ci		wq->to_use = buf->next;
81462306a36Sopenharmony_ci		dev_kfree_skb(skb);
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci	return err;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci/* netif_tx_lock held, process context with BHs disabled, or BH */
82062306a36Sopenharmony_cistatic netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
82162306a36Sopenharmony_ci	struct net_device *netdev)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
82462306a36Sopenharmony_ci	struct vnic_wq *wq;
82562306a36Sopenharmony_ci	unsigned int txq_map;
82662306a36Sopenharmony_ci	struct netdev_queue *txq;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	if (skb->len <= 0) {
82962306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
83062306a36Sopenharmony_ci		return NETDEV_TX_OK;
83162306a36Sopenharmony_ci	}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	txq_map = skb_get_queue_mapping(skb) % enic->wq_count;
83462306a36Sopenharmony_ci	wq = &enic->wq[txq_map];
83562306a36Sopenharmony_ci	txq = netdev_get_tx_queue(netdev, txq_map);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	/* Non-TSO sends must fit within ENIC_NON_TSO_MAX_DESC descs,
83862306a36Sopenharmony_ci	 * which is very likely.  In the off chance it's going to take
83962306a36Sopenharmony_ci	 * more than * ENIC_NON_TSO_MAX_DESC, linearize the skb.
84062306a36Sopenharmony_ci	 */
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	if (skb_shinfo(skb)->gso_size == 0 &&
84362306a36Sopenharmony_ci	    skb_shinfo(skb)->nr_frags + 1 > ENIC_NON_TSO_MAX_DESC &&
84462306a36Sopenharmony_ci	    skb_linearize(skb)) {
84562306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
84662306a36Sopenharmony_ci		return NETDEV_TX_OK;
84762306a36Sopenharmony_ci	}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	spin_lock(&enic->wq_lock[txq_map]);
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	if (vnic_wq_desc_avail(wq) <
85262306a36Sopenharmony_ci	    skb_shinfo(skb)->nr_frags + ENIC_DESC_MAX_SPLITS) {
85362306a36Sopenharmony_ci		netif_tx_stop_queue(txq);
85462306a36Sopenharmony_ci		/* This is a hard error, log it */
85562306a36Sopenharmony_ci		netdev_err(netdev, "BUG! Tx ring full when queue awake!\n");
85662306a36Sopenharmony_ci		spin_unlock(&enic->wq_lock[txq_map]);
85762306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	if (enic_queue_wq_skb(enic, wq, skb))
86162306a36Sopenharmony_ci		goto error;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	if (vnic_wq_desc_avail(wq) < MAX_SKB_FRAGS + ENIC_DESC_MAX_SPLITS)
86462306a36Sopenharmony_ci		netif_tx_stop_queue(txq);
86562306a36Sopenharmony_ci	skb_tx_timestamp(skb);
86662306a36Sopenharmony_ci	if (!netdev_xmit_more() || netif_xmit_stopped(txq))
86762306a36Sopenharmony_ci		vnic_wq_doorbell(wq);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cierror:
87062306a36Sopenharmony_ci	spin_unlock(&enic->wq_lock[txq_map]);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	return NETDEV_TX_OK;
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci/* dev_base_lock rwlock held, nominally process context */
87662306a36Sopenharmony_cistatic void enic_get_stats(struct net_device *netdev,
87762306a36Sopenharmony_ci			   struct rtnl_link_stats64 *net_stats)
87862306a36Sopenharmony_ci{
87962306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
88062306a36Sopenharmony_ci	struct vnic_stats *stats;
88162306a36Sopenharmony_ci	int err;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	err = enic_dev_stats_dump(enic, &stats);
88462306a36Sopenharmony_ci	/* return only when dma_alloc_coherent fails in vnic_dev_stats_dump
88562306a36Sopenharmony_ci	 * For other failures, like devcmd failure, we return previously
88662306a36Sopenharmony_ci	 * recorded stats.
88762306a36Sopenharmony_ci	 */
88862306a36Sopenharmony_ci	if (err == -ENOMEM)
88962306a36Sopenharmony_ci		return;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	net_stats->tx_packets = stats->tx.tx_frames_ok;
89262306a36Sopenharmony_ci	net_stats->tx_bytes = stats->tx.tx_bytes_ok;
89362306a36Sopenharmony_ci	net_stats->tx_errors = stats->tx.tx_errors;
89462306a36Sopenharmony_ci	net_stats->tx_dropped = stats->tx.tx_drops;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	net_stats->rx_packets = stats->rx.rx_frames_ok;
89762306a36Sopenharmony_ci	net_stats->rx_bytes = stats->rx.rx_bytes_ok;
89862306a36Sopenharmony_ci	net_stats->rx_errors = stats->rx.rx_errors;
89962306a36Sopenharmony_ci	net_stats->multicast = stats->rx.rx_multicast_frames_ok;
90062306a36Sopenharmony_ci	net_stats->rx_over_errors = enic->rq_truncated_pkts;
90162306a36Sopenharmony_ci	net_stats->rx_crc_errors = enic->rq_bad_fcs;
90262306a36Sopenharmony_ci	net_stats->rx_dropped = stats->rx.rx_no_bufs + stats->rx.rx_drop;
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cistatic int enic_mc_sync(struct net_device *netdev, const u8 *mc_addr)
90662306a36Sopenharmony_ci{
90762306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci	if (enic->mc_count == ENIC_MULTICAST_PERFECT_FILTERS) {
91062306a36Sopenharmony_ci		unsigned int mc_count = netdev_mc_count(netdev);
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci		netdev_warn(netdev, "Registering only %d out of %d multicast addresses\n",
91362306a36Sopenharmony_ci			    ENIC_MULTICAST_PERFECT_FILTERS, mc_count);
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci		return -ENOSPC;
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	enic_dev_add_addr(enic, mc_addr);
91962306a36Sopenharmony_ci	enic->mc_count++;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	return 0;
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic int enic_mc_unsync(struct net_device *netdev, const u8 *mc_addr)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	enic_dev_del_addr(enic, mc_addr);
92962306a36Sopenharmony_ci	enic->mc_count--;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	return 0;
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic int enic_uc_sync(struct net_device *netdev, const u8 *uc_addr)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	if (enic->uc_count == ENIC_UNICAST_PERFECT_FILTERS) {
93962306a36Sopenharmony_ci		unsigned int uc_count = netdev_uc_count(netdev);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci		netdev_warn(netdev, "Registering only %d out of %d unicast addresses\n",
94262306a36Sopenharmony_ci			    ENIC_UNICAST_PERFECT_FILTERS, uc_count);
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		return -ENOSPC;
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	enic_dev_add_addr(enic, uc_addr);
94862306a36Sopenharmony_ci	enic->uc_count++;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	return 0;
95162306a36Sopenharmony_ci}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_cistatic int enic_uc_unsync(struct net_device *netdev, const u8 *uc_addr)
95462306a36Sopenharmony_ci{
95562306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	enic_dev_del_addr(enic, uc_addr);
95862306a36Sopenharmony_ci	enic->uc_count--;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	return 0;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_civoid enic_reset_addr_lists(struct enic *enic)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	struct net_device *netdev = enic->netdev;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	__dev_uc_unsync(netdev, NULL);
96862306a36Sopenharmony_ci	__dev_mc_unsync(netdev, NULL);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	enic->mc_count = 0;
97162306a36Sopenharmony_ci	enic->uc_count = 0;
97262306a36Sopenharmony_ci	enic->flags = 0;
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic int enic_set_mac_addr(struct net_device *netdev, char *addr)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic)) {
98062306a36Sopenharmony_ci		if (!is_valid_ether_addr(addr) && !is_zero_ether_addr(addr))
98162306a36Sopenharmony_ci			return -EADDRNOTAVAIL;
98262306a36Sopenharmony_ci	} else {
98362306a36Sopenharmony_ci		if (!is_valid_ether_addr(addr))
98462306a36Sopenharmony_ci			return -EADDRNOTAVAIL;
98562306a36Sopenharmony_ci	}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	eth_hw_addr_set(netdev, addr);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	return 0;
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic int enic_set_mac_address_dynamic(struct net_device *netdev, void *p)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
99562306a36Sopenharmony_ci	struct sockaddr *saddr = p;
99662306a36Sopenharmony_ci	char *addr = saddr->sa_data;
99762306a36Sopenharmony_ci	int err;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	if (netif_running(enic->netdev)) {
100062306a36Sopenharmony_ci		err = enic_dev_del_station_addr(enic);
100162306a36Sopenharmony_ci		if (err)
100262306a36Sopenharmony_ci			return err;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	err = enic_set_mac_addr(netdev, addr);
100662306a36Sopenharmony_ci	if (err)
100762306a36Sopenharmony_ci		return err;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (netif_running(enic->netdev)) {
101062306a36Sopenharmony_ci		err = enic_dev_add_station_addr(enic);
101162306a36Sopenharmony_ci		if (err)
101262306a36Sopenharmony_ci			return err;
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	return err;
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic int enic_set_mac_address(struct net_device *netdev, void *p)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	struct sockaddr *saddr = p;
102162306a36Sopenharmony_ci	char *addr = saddr->sa_data;
102262306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
102362306a36Sopenharmony_ci	int err;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	err = enic_dev_del_station_addr(enic);
102662306a36Sopenharmony_ci	if (err)
102762306a36Sopenharmony_ci		return err;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	err = enic_set_mac_addr(netdev, addr);
103062306a36Sopenharmony_ci	if (err)
103162306a36Sopenharmony_ci		return err;
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	return enic_dev_add_station_addr(enic);
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci/* netif_tx_lock held, BHs disabled */
103762306a36Sopenharmony_cistatic void enic_set_rx_mode(struct net_device *netdev)
103862306a36Sopenharmony_ci{
103962306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
104062306a36Sopenharmony_ci	int directed = 1;
104162306a36Sopenharmony_ci	int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0;
104262306a36Sopenharmony_ci	int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0;
104362306a36Sopenharmony_ci	int promisc = (netdev->flags & IFF_PROMISC) ||
104462306a36Sopenharmony_ci		netdev_uc_count(netdev) > ENIC_UNICAST_PERFECT_FILTERS;
104562306a36Sopenharmony_ci	int allmulti = (netdev->flags & IFF_ALLMULTI) ||
104662306a36Sopenharmony_ci		netdev_mc_count(netdev) > ENIC_MULTICAST_PERFECT_FILTERS;
104762306a36Sopenharmony_ci	unsigned int flags = netdev->flags |
104862306a36Sopenharmony_ci		(allmulti ? IFF_ALLMULTI : 0) |
104962306a36Sopenharmony_ci		(promisc ? IFF_PROMISC : 0);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	if (enic->flags != flags) {
105262306a36Sopenharmony_ci		enic->flags = flags;
105362306a36Sopenharmony_ci		enic_dev_packet_filter(enic, directed,
105462306a36Sopenharmony_ci			multicast, broadcast, promisc, allmulti);
105562306a36Sopenharmony_ci	}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	if (!promisc) {
105862306a36Sopenharmony_ci		__dev_uc_sync(netdev, enic_uc_sync, enic_uc_unsync);
105962306a36Sopenharmony_ci		if (!allmulti)
106062306a36Sopenharmony_ci			__dev_mc_sync(netdev, enic_mc_sync, enic_mc_unsync);
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci/* netif_tx_lock held, BHs disabled */
106562306a36Sopenharmony_cistatic void enic_tx_timeout(struct net_device *netdev, unsigned int txqueue)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
106862306a36Sopenharmony_ci	schedule_work(&enic->tx_hang_reset);
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_cistatic int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
107462306a36Sopenharmony_ci	struct enic_port_profile *pp;
107562306a36Sopenharmony_ci	int err;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
107862306a36Sopenharmony_ci	if (err)
107962306a36Sopenharmony_ci		return err;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	if (is_valid_ether_addr(mac) || is_zero_ether_addr(mac)) {
108262306a36Sopenharmony_ci		if (vf == PORT_SELF_VF) {
108362306a36Sopenharmony_ci			memcpy(pp->vf_mac, mac, ETH_ALEN);
108462306a36Sopenharmony_ci			return 0;
108562306a36Sopenharmony_ci		} else {
108662306a36Sopenharmony_ci			/*
108762306a36Sopenharmony_ci			 * For sriov vf's set the mac in hw
108862306a36Sopenharmony_ci			 */
108962306a36Sopenharmony_ci			ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
109062306a36Sopenharmony_ci				vnic_dev_set_mac_addr, mac);
109162306a36Sopenharmony_ci			return enic_dev_status_to_errno(err);
109262306a36Sopenharmony_ci		}
109362306a36Sopenharmony_ci	} else
109462306a36Sopenharmony_ci		return -EINVAL;
109562306a36Sopenharmony_ci}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_cistatic int enic_set_vf_port(struct net_device *netdev, int vf,
109862306a36Sopenharmony_ci	struct nlattr *port[])
109962306a36Sopenharmony_ci{
110062306a36Sopenharmony_ci	static const u8 zero_addr[ETH_ALEN] = {};
110162306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
110262306a36Sopenharmony_ci	struct enic_port_profile prev_pp;
110362306a36Sopenharmony_ci	struct enic_port_profile *pp;
110462306a36Sopenharmony_ci	int err = 0, restore_pp = 1;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
110762306a36Sopenharmony_ci	if (err)
110862306a36Sopenharmony_ci		return err;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	if (!port[IFLA_PORT_REQUEST])
111162306a36Sopenharmony_ci		return -EOPNOTSUPP;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	memcpy(&prev_pp, pp, sizeof(*enic->pp));
111462306a36Sopenharmony_ci	memset(pp, 0, sizeof(*enic->pp));
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	pp->set |= ENIC_SET_REQUEST;
111762306a36Sopenharmony_ci	pp->request = nla_get_u8(port[IFLA_PORT_REQUEST]);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if (port[IFLA_PORT_PROFILE]) {
112062306a36Sopenharmony_ci		pp->set |= ENIC_SET_NAME;
112162306a36Sopenharmony_ci		memcpy(pp->name, nla_data(port[IFLA_PORT_PROFILE]),
112262306a36Sopenharmony_ci			PORT_PROFILE_MAX);
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	if (port[IFLA_PORT_INSTANCE_UUID]) {
112662306a36Sopenharmony_ci		pp->set |= ENIC_SET_INSTANCE;
112762306a36Sopenharmony_ci		memcpy(pp->instance_uuid,
112862306a36Sopenharmony_ci			nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	if (port[IFLA_PORT_HOST_UUID]) {
113262306a36Sopenharmony_ci		pp->set |= ENIC_SET_HOST;
113362306a36Sopenharmony_ci		memcpy(pp->host_uuid,
113462306a36Sopenharmony_ci			nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (vf == PORT_SELF_VF) {
113862306a36Sopenharmony_ci		/* Special case handling: mac came from IFLA_VF_MAC */
113962306a36Sopenharmony_ci		if (!is_zero_ether_addr(prev_pp.vf_mac))
114062306a36Sopenharmony_ci			memcpy(pp->mac_addr, prev_pp.vf_mac, ETH_ALEN);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		if (is_zero_ether_addr(netdev->dev_addr))
114362306a36Sopenharmony_ci			eth_hw_addr_random(netdev);
114462306a36Sopenharmony_ci	} else {
114562306a36Sopenharmony_ci		/* SR-IOV VF: get mac from adapter */
114662306a36Sopenharmony_ci		ENIC_DEVCMD_PROXY_BY_INDEX(vf, err, enic,
114762306a36Sopenharmony_ci			vnic_dev_get_mac_addr, pp->mac_addr);
114862306a36Sopenharmony_ci		if (err) {
114962306a36Sopenharmony_ci			netdev_err(netdev, "Error getting mac for vf %d\n", vf);
115062306a36Sopenharmony_ci			memcpy(pp, &prev_pp, sizeof(*pp));
115162306a36Sopenharmony_ci			return enic_dev_status_to_errno(err);
115262306a36Sopenharmony_ci		}
115362306a36Sopenharmony_ci	}
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	err = enic_process_set_pp_request(enic, vf, &prev_pp, &restore_pp);
115662306a36Sopenharmony_ci	if (err) {
115762306a36Sopenharmony_ci		if (restore_pp) {
115862306a36Sopenharmony_ci			/* Things are still the way they were: Implicit
115962306a36Sopenharmony_ci			 * DISASSOCIATE failed
116062306a36Sopenharmony_ci			 */
116162306a36Sopenharmony_ci			memcpy(pp, &prev_pp, sizeof(*pp));
116262306a36Sopenharmony_ci		} else {
116362306a36Sopenharmony_ci			memset(pp, 0, sizeof(*pp));
116462306a36Sopenharmony_ci			if (vf == PORT_SELF_VF)
116562306a36Sopenharmony_ci				eth_hw_addr_set(netdev, zero_addr);
116662306a36Sopenharmony_ci		}
116762306a36Sopenharmony_ci	} else {
116862306a36Sopenharmony_ci		/* Set flag to indicate that the port assoc/disassoc
116962306a36Sopenharmony_ci		 * request has been sent out to fw
117062306a36Sopenharmony_ci		 */
117162306a36Sopenharmony_ci		pp->set |= ENIC_PORT_REQUEST_APPLIED;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci		/* If DISASSOCIATE, clean up all assigned/saved macaddresses */
117462306a36Sopenharmony_ci		if (pp->request == PORT_REQUEST_DISASSOCIATE) {
117562306a36Sopenharmony_ci			eth_zero_addr(pp->mac_addr);
117662306a36Sopenharmony_ci			if (vf == PORT_SELF_VF)
117762306a36Sopenharmony_ci				eth_hw_addr_set(netdev, zero_addr);
117862306a36Sopenharmony_ci		}
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	if (vf == PORT_SELF_VF)
118262306a36Sopenharmony_ci		eth_zero_addr(pp->vf_mac);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	return err;
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_cistatic int enic_get_vf_port(struct net_device *netdev, int vf,
118862306a36Sopenharmony_ci	struct sk_buff *skb)
118962306a36Sopenharmony_ci{
119062306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
119162306a36Sopenharmony_ci	u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
119262306a36Sopenharmony_ci	struct enic_port_profile *pp;
119362306a36Sopenharmony_ci	int err;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	ENIC_PP_BY_INDEX(enic, vf, pp, &err);
119662306a36Sopenharmony_ci	if (err)
119762306a36Sopenharmony_ci		return err;
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci	if (!(pp->set & ENIC_PORT_REQUEST_APPLIED))
120062306a36Sopenharmony_ci		return -ENODATA;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	err = enic_process_get_pp_request(enic, vf, pp->request, &response);
120362306a36Sopenharmony_ci	if (err)
120462306a36Sopenharmony_ci		return err;
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	if (nla_put_u16(skb, IFLA_PORT_REQUEST, pp->request) ||
120762306a36Sopenharmony_ci	    nla_put_u16(skb, IFLA_PORT_RESPONSE, response) ||
120862306a36Sopenharmony_ci	    ((pp->set & ENIC_SET_NAME) &&
120962306a36Sopenharmony_ci	     nla_put(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX, pp->name)) ||
121062306a36Sopenharmony_ci	    ((pp->set & ENIC_SET_INSTANCE) &&
121162306a36Sopenharmony_ci	     nla_put(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
121262306a36Sopenharmony_ci		     pp->instance_uuid)) ||
121362306a36Sopenharmony_ci	    ((pp->set & ENIC_SET_HOST) &&
121462306a36Sopenharmony_ci	     nla_put(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX, pp->host_uuid)))
121562306a36Sopenharmony_ci		goto nla_put_failure;
121662306a36Sopenharmony_ci	return 0;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_cinla_put_failure:
121962306a36Sopenharmony_ci	return -EMSGSIZE;
122062306a36Sopenharmony_ci}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_cistatic void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
122362306a36Sopenharmony_ci{
122462306a36Sopenharmony_ci	struct enic *enic = vnic_dev_priv(rq->vdev);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (!buf->os_buf)
122762306a36Sopenharmony_ci		return;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	dma_unmap_single(&enic->pdev->dev, buf->dma_addr, buf->len,
123062306a36Sopenharmony_ci			 DMA_FROM_DEVICE);
123162306a36Sopenharmony_ci	dev_kfree_skb_any(buf->os_buf);
123262306a36Sopenharmony_ci	buf->os_buf = NULL;
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic int enic_rq_alloc_buf(struct vnic_rq *rq)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct enic *enic = vnic_dev_priv(rq->vdev);
123862306a36Sopenharmony_ci	struct net_device *netdev = enic->netdev;
123962306a36Sopenharmony_ci	struct sk_buff *skb;
124062306a36Sopenharmony_ci	unsigned int len = netdev->mtu + VLAN_ETH_HLEN;
124162306a36Sopenharmony_ci	unsigned int os_buf_index = 0;
124262306a36Sopenharmony_ci	dma_addr_t dma_addr;
124362306a36Sopenharmony_ci	struct vnic_rq_buf *buf = rq->to_use;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (buf->os_buf) {
124662306a36Sopenharmony_ci		enic_queue_rq_desc(rq, buf->os_buf, os_buf_index, buf->dma_addr,
124762306a36Sopenharmony_ci				   buf->len);
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci		return 0;
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci	skb = netdev_alloc_skb_ip_align(netdev, len);
125262306a36Sopenharmony_ci	if (!skb)
125362306a36Sopenharmony_ci		return -ENOMEM;
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	dma_addr = dma_map_single(&enic->pdev->dev, skb->data, len,
125662306a36Sopenharmony_ci				  DMA_FROM_DEVICE);
125762306a36Sopenharmony_ci	if (unlikely(enic_dma_map_check(enic, dma_addr))) {
125862306a36Sopenharmony_ci		dev_kfree_skb(skb);
125962306a36Sopenharmony_ci		return -ENOMEM;
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	enic_queue_rq_desc(rq, skb, os_buf_index,
126362306a36Sopenharmony_ci		dma_addr, len);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	return 0;
126662306a36Sopenharmony_ci}
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_cistatic void enic_intr_update_pkt_size(struct vnic_rx_bytes_counter *pkt_size,
126962306a36Sopenharmony_ci				      u32 pkt_len)
127062306a36Sopenharmony_ci{
127162306a36Sopenharmony_ci	if (ENIC_LARGE_PKT_THRESHOLD <= pkt_len)
127262306a36Sopenharmony_ci		pkt_size->large_pkt_bytes_cnt += pkt_len;
127362306a36Sopenharmony_ci	else
127462306a36Sopenharmony_ci		pkt_size->small_pkt_bytes_cnt += pkt_len;
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cistatic bool enic_rxcopybreak(struct net_device *netdev, struct sk_buff **skb,
127862306a36Sopenharmony_ci			     struct vnic_rq_buf *buf, u16 len)
127962306a36Sopenharmony_ci{
128062306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
128162306a36Sopenharmony_ci	struct sk_buff *new_skb;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	if (len > enic->rx_copybreak)
128462306a36Sopenharmony_ci		return false;
128562306a36Sopenharmony_ci	new_skb = netdev_alloc_skb_ip_align(netdev, len);
128662306a36Sopenharmony_ci	if (!new_skb)
128762306a36Sopenharmony_ci		return false;
128862306a36Sopenharmony_ci	dma_sync_single_for_cpu(&enic->pdev->dev, buf->dma_addr, len,
128962306a36Sopenharmony_ci				DMA_FROM_DEVICE);
129062306a36Sopenharmony_ci	memcpy(new_skb->data, (*skb)->data, len);
129162306a36Sopenharmony_ci	*skb = new_skb;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	return true;
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_cistatic void enic_rq_indicate_buf(struct vnic_rq *rq,
129762306a36Sopenharmony_ci	struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
129862306a36Sopenharmony_ci	int skipped, void *opaque)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	struct enic *enic = vnic_dev_priv(rq->vdev);
130162306a36Sopenharmony_ci	struct net_device *netdev = enic->netdev;
130262306a36Sopenharmony_ci	struct sk_buff *skb;
130362306a36Sopenharmony_ci	struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)];
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	u8 type, color, eop, sop, ingress_port, vlan_stripped;
130662306a36Sopenharmony_ci	u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof;
130762306a36Sopenharmony_ci	u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok;
130862306a36Sopenharmony_ci	u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc;
130962306a36Sopenharmony_ci	u8 packet_error;
131062306a36Sopenharmony_ci	u16 q_number, completed_index, bytes_written, vlan_tci, checksum;
131162306a36Sopenharmony_ci	u32 rss_hash;
131262306a36Sopenharmony_ci	bool outer_csum_ok = true, encap = false;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	if (skipped)
131562306a36Sopenharmony_ci		return;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	skb = buf->os_buf;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc,
132062306a36Sopenharmony_ci		&type, &color, &q_number, &completed_index,
132162306a36Sopenharmony_ci		&ingress_port, &fcoe, &eop, &sop, &rss_type,
132262306a36Sopenharmony_ci		&csum_not_calc, &rss_hash, &bytes_written,
132362306a36Sopenharmony_ci		&packet_error, &vlan_stripped, &vlan_tci, &checksum,
132462306a36Sopenharmony_ci		&fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error,
132562306a36Sopenharmony_ci		&fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp,
132662306a36Sopenharmony_ci		&ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment,
132762306a36Sopenharmony_ci		&fcs_ok);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	if (packet_error) {
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci		if (!fcs_ok) {
133262306a36Sopenharmony_ci			if (bytes_written > 0)
133362306a36Sopenharmony_ci				enic->rq_bad_fcs++;
133462306a36Sopenharmony_ci			else if (bytes_written == 0)
133562306a36Sopenharmony_ci				enic->rq_truncated_pkts++;
133662306a36Sopenharmony_ci		}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci		dma_unmap_single(&enic->pdev->dev, buf->dma_addr, buf->len,
133962306a36Sopenharmony_ci				 DMA_FROM_DEVICE);
134062306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
134162306a36Sopenharmony_ci		buf->os_buf = NULL;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci		return;
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	if (eop && bytes_written > 0) {
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci		/* Good receive
134962306a36Sopenharmony_ci		 */
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci		if (!enic_rxcopybreak(netdev, &skb, buf, bytes_written)) {
135262306a36Sopenharmony_ci			buf->os_buf = NULL;
135362306a36Sopenharmony_ci			dma_unmap_single(&enic->pdev->dev, buf->dma_addr,
135462306a36Sopenharmony_ci					 buf->len, DMA_FROM_DEVICE);
135562306a36Sopenharmony_ci		}
135662306a36Sopenharmony_ci		prefetch(skb->data - NET_IP_ALIGN);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci		skb_put(skb, bytes_written);
135962306a36Sopenharmony_ci		skb->protocol = eth_type_trans(skb, netdev);
136062306a36Sopenharmony_ci		skb_record_rx_queue(skb, q_number);
136162306a36Sopenharmony_ci		if ((netdev->features & NETIF_F_RXHASH) && rss_hash &&
136262306a36Sopenharmony_ci		    (type == 3)) {
136362306a36Sopenharmony_ci			switch (rss_type) {
136462306a36Sopenharmony_ci			case CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv4:
136562306a36Sopenharmony_ci			case CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6:
136662306a36Sopenharmony_ci			case CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6_EX:
136762306a36Sopenharmony_ci				skb_set_hash(skb, rss_hash, PKT_HASH_TYPE_L4);
136862306a36Sopenharmony_ci				break;
136962306a36Sopenharmony_ci			case CQ_ENET_RQ_DESC_RSS_TYPE_IPv4:
137062306a36Sopenharmony_ci			case CQ_ENET_RQ_DESC_RSS_TYPE_IPv6:
137162306a36Sopenharmony_ci			case CQ_ENET_RQ_DESC_RSS_TYPE_IPv6_EX:
137262306a36Sopenharmony_ci				skb_set_hash(skb, rss_hash, PKT_HASH_TYPE_L3);
137362306a36Sopenharmony_ci				break;
137462306a36Sopenharmony_ci			}
137562306a36Sopenharmony_ci		}
137662306a36Sopenharmony_ci		if (enic->vxlan.vxlan_udp_port_number) {
137762306a36Sopenharmony_ci			switch (enic->vxlan.patch_level) {
137862306a36Sopenharmony_ci			case 0:
137962306a36Sopenharmony_ci				if (fcoe) {
138062306a36Sopenharmony_ci					encap = true;
138162306a36Sopenharmony_ci					outer_csum_ok = fcoe_fc_crc_ok;
138262306a36Sopenharmony_ci				}
138362306a36Sopenharmony_ci				break;
138462306a36Sopenharmony_ci			case 2:
138562306a36Sopenharmony_ci				if ((type == 7) &&
138662306a36Sopenharmony_ci				    (rss_hash & BIT(0))) {
138762306a36Sopenharmony_ci					encap = true;
138862306a36Sopenharmony_ci					outer_csum_ok = (rss_hash & BIT(1)) &&
138962306a36Sopenharmony_ci							(rss_hash & BIT(2));
139062306a36Sopenharmony_ci				}
139162306a36Sopenharmony_ci				break;
139262306a36Sopenharmony_ci			}
139362306a36Sopenharmony_ci		}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci		/* Hardware does not provide whole packet checksum. It only
139662306a36Sopenharmony_ci		 * provides pseudo checksum. Since hw validates the packet
139762306a36Sopenharmony_ci		 * checksum but not provide us the checksum value. use
139862306a36Sopenharmony_ci		 * CHECSUM_UNNECESSARY.
139962306a36Sopenharmony_ci		 *
140062306a36Sopenharmony_ci		 * In case of encap pkt tcp_udp_csum_ok/tcp_udp_csum_ok is
140162306a36Sopenharmony_ci		 * inner csum_ok. outer_csum_ok is set by hw when outer udp
140262306a36Sopenharmony_ci		 * csum is correct or is zero.
140362306a36Sopenharmony_ci		 */
140462306a36Sopenharmony_ci		if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc &&
140562306a36Sopenharmony_ci		    tcp_udp_csum_ok && outer_csum_ok &&
140662306a36Sopenharmony_ci		    (ipv4_csum_ok || ipv6)) {
140762306a36Sopenharmony_ci			skb->ip_summed = CHECKSUM_UNNECESSARY;
140862306a36Sopenharmony_ci			skb->csum_level = encap;
140962306a36Sopenharmony_ci		}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci		if (vlan_stripped)
141262306a36Sopenharmony_ci			__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci		skb_mark_napi_id(skb, &enic->napi[rq->index]);
141562306a36Sopenharmony_ci		if (!(netdev->features & NETIF_F_GRO))
141662306a36Sopenharmony_ci			netif_receive_skb(skb);
141762306a36Sopenharmony_ci		else
141862306a36Sopenharmony_ci			napi_gro_receive(&enic->napi[q_number], skb);
141962306a36Sopenharmony_ci		if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
142062306a36Sopenharmony_ci			enic_intr_update_pkt_size(&cq->pkt_size_counter,
142162306a36Sopenharmony_ci						  bytes_written);
142262306a36Sopenharmony_ci	} else {
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci		/* Buffer overflow
142562306a36Sopenharmony_ci		 */
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci		dma_unmap_single(&enic->pdev->dev, buf->dma_addr, buf->len,
142862306a36Sopenharmony_ci				 DMA_FROM_DEVICE);
142962306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
143062306a36Sopenharmony_ci		buf->os_buf = NULL;
143162306a36Sopenharmony_ci	}
143262306a36Sopenharmony_ci}
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_cistatic int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
143562306a36Sopenharmony_ci	u8 type, u16 q_number, u16 completed_index, void *opaque)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct enic *enic = vnic_dev_priv(vdev);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	vnic_rq_service(&enic->rq[q_number], cq_desc,
144062306a36Sopenharmony_ci		completed_index, VNIC_RQ_RETURN_DESC,
144162306a36Sopenharmony_ci		enic_rq_indicate_buf, opaque);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	return 0;
144462306a36Sopenharmony_ci}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_cistatic void enic_set_int_moderation(struct enic *enic, struct vnic_rq *rq)
144762306a36Sopenharmony_ci{
144862306a36Sopenharmony_ci	unsigned int intr = enic_msix_rq_intr(enic, rq->index);
144962306a36Sopenharmony_ci	struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)];
145062306a36Sopenharmony_ci	u32 timer = cq->tobe_rx_coal_timeval;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	if (cq->tobe_rx_coal_timeval != cq->cur_rx_coal_timeval) {
145362306a36Sopenharmony_ci		vnic_intr_coalescing_timer_set(&enic->intr[intr], timer);
145462306a36Sopenharmony_ci		cq->cur_rx_coal_timeval = cq->tobe_rx_coal_timeval;
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci}
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_cistatic void enic_calc_int_moderation(struct enic *enic, struct vnic_rq *rq)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting;
146162306a36Sopenharmony_ci	struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)];
146262306a36Sopenharmony_ci	struct vnic_rx_bytes_counter *pkt_size_counter = &cq->pkt_size_counter;
146362306a36Sopenharmony_ci	int index;
146462306a36Sopenharmony_ci	u32 timer;
146562306a36Sopenharmony_ci	u32 range_start;
146662306a36Sopenharmony_ci	u32 traffic;
146762306a36Sopenharmony_ci	u64 delta;
146862306a36Sopenharmony_ci	ktime_t now = ktime_get();
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	delta = ktime_us_delta(now, cq->prev_ts);
147162306a36Sopenharmony_ci	if (delta < ENIC_AIC_TS_BREAK)
147262306a36Sopenharmony_ci		return;
147362306a36Sopenharmony_ci	cq->prev_ts = now;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	traffic = pkt_size_counter->large_pkt_bytes_cnt +
147662306a36Sopenharmony_ci		  pkt_size_counter->small_pkt_bytes_cnt;
147762306a36Sopenharmony_ci	/* The table takes Mbps
147862306a36Sopenharmony_ci	 * traffic *= 8    => bits
147962306a36Sopenharmony_ci	 * traffic *= (10^6 / delta)    => bps
148062306a36Sopenharmony_ci	 * traffic /= 10^6     => Mbps
148162306a36Sopenharmony_ci	 *
148262306a36Sopenharmony_ci	 * Combining, traffic *= (8 / delta)
148362306a36Sopenharmony_ci	 */
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	traffic <<= 3;
148662306a36Sopenharmony_ci	traffic = delta > UINT_MAX ? 0 : traffic / (u32)delta;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	for (index = 0; index < ENIC_MAX_COALESCE_TIMERS; index++)
148962306a36Sopenharmony_ci		if (traffic < mod_table[index].rx_rate)
149062306a36Sopenharmony_ci			break;
149162306a36Sopenharmony_ci	range_start = (pkt_size_counter->small_pkt_bytes_cnt >
149262306a36Sopenharmony_ci		       pkt_size_counter->large_pkt_bytes_cnt << 1) ?
149362306a36Sopenharmony_ci		      rx_coal->small_pkt_range_start :
149462306a36Sopenharmony_ci		      rx_coal->large_pkt_range_start;
149562306a36Sopenharmony_ci	timer = range_start + ((rx_coal->range_end - range_start) *
149662306a36Sopenharmony_ci			       mod_table[index].range_percent / 100);
149762306a36Sopenharmony_ci	/* Damping */
149862306a36Sopenharmony_ci	cq->tobe_rx_coal_timeval = (timer + cq->tobe_rx_coal_timeval) >> 1;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	pkt_size_counter->large_pkt_bytes_cnt = 0;
150162306a36Sopenharmony_ci	pkt_size_counter->small_pkt_bytes_cnt = 0;
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_cistatic int enic_poll(struct napi_struct *napi, int budget)
150562306a36Sopenharmony_ci{
150662306a36Sopenharmony_ci	struct net_device *netdev = napi->dev;
150762306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
150862306a36Sopenharmony_ci	unsigned int cq_rq = enic_cq_rq(enic, 0);
150962306a36Sopenharmony_ci	unsigned int cq_wq = enic_cq_wq(enic, 0);
151062306a36Sopenharmony_ci	unsigned int intr = ENIC_LEGACY_IO_INTR;
151162306a36Sopenharmony_ci	unsigned int rq_work_to_do = budget;
151262306a36Sopenharmony_ci	unsigned int wq_work_to_do = ENIC_WQ_NAPI_BUDGET;
151362306a36Sopenharmony_ci	unsigned int  work_done, rq_work_done = 0, wq_work_done;
151462306a36Sopenharmony_ci	int err;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	wq_work_done = vnic_cq_service(&enic->cq[cq_wq], wq_work_to_do,
151762306a36Sopenharmony_ci				       enic_wq_service, NULL);
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	if (budget > 0)
152062306a36Sopenharmony_ci		rq_work_done = vnic_cq_service(&enic->cq[cq_rq],
152162306a36Sopenharmony_ci			rq_work_to_do, enic_rq_service, NULL);
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	/* Accumulate intr event credits for this polling
152462306a36Sopenharmony_ci	 * cycle.  An intr event is the completion of a
152562306a36Sopenharmony_ci	 * a WQ or RQ packet.
152662306a36Sopenharmony_ci	 */
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	work_done = rq_work_done + wq_work_done;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	if (work_done > 0)
153162306a36Sopenharmony_ci		vnic_intr_return_credits(&enic->intr[intr],
153262306a36Sopenharmony_ci			work_done,
153362306a36Sopenharmony_ci			0 /* don't unmask intr */,
153462306a36Sopenharmony_ci			0 /* don't reset intr timer */);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	err = vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	/* Buffer allocation failed. Stay in polling
153962306a36Sopenharmony_ci	 * mode so we can try to fill the ring again.
154062306a36Sopenharmony_ci	 */
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	if (err)
154362306a36Sopenharmony_ci		rq_work_done = rq_work_to_do;
154462306a36Sopenharmony_ci	if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
154562306a36Sopenharmony_ci		/* Call the function which refreshes the intr coalescing timer
154662306a36Sopenharmony_ci		 * value based on the traffic.
154762306a36Sopenharmony_ci		 */
154862306a36Sopenharmony_ci		enic_calc_int_moderation(enic, &enic->rq[0]);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	if ((rq_work_done < budget) && napi_complete_done(napi, rq_work_done)) {
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci		/* Some work done, but not enough to stay in polling,
155362306a36Sopenharmony_ci		 * exit polling
155462306a36Sopenharmony_ci		 */
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci		if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
155762306a36Sopenharmony_ci			enic_set_int_moderation(enic, &enic->rq[0]);
155862306a36Sopenharmony_ci		vnic_intr_unmask(&enic->intr[intr]);
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci	return rq_work_done;
156262306a36Sopenharmony_ci}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
156562306a36Sopenharmony_cistatic void enic_free_rx_cpu_rmap(struct enic *enic)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	free_irq_cpu_rmap(enic->netdev->rx_cpu_rmap);
156862306a36Sopenharmony_ci	enic->netdev->rx_cpu_rmap = NULL;
156962306a36Sopenharmony_ci}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_cistatic void enic_set_rx_cpu_rmap(struct enic *enic)
157262306a36Sopenharmony_ci{
157362306a36Sopenharmony_ci	int i, res;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) {
157662306a36Sopenharmony_ci		enic->netdev->rx_cpu_rmap = alloc_irq_cpu_rmap(enic->rq_count);
157762306a36Sopenharmony_ci		if (unlikely(!enic->netdev->rx_cpu_rmap))
157862306a36Sopenharmony_ci			return;
157962306a36Sopenharmony_ci		for (i = 0; i < enic->rq_count; i++) {
158062306a36Sopenharmony_ci			res = irq_cpu_rmap_add(enic->netdev->rx_cpu_rmap,
158162306a36Sopenharmony_ci					       enic->msix_entry[i].vector);
158262306a36Sopenharmony_ci			if (unlikely(res)) {
158362306a36Sopenharmony_ci				enic_free_rx_cpu_rmap(enic);
158462306a36Sopenharmony_ci				return;
158562306a36Sopenharmony_ci			}
158662306a36Sopenharmony_ci		}
158762306a36Sopenharmony_ci	}
158862306a36Sopenharmony_ci}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci#else
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_cistatic void enic_free_rx_cpu_rmap(struct enic *enic)
159362306a36Sopenharmony_ci{
159462306a36Sopenharmony_ci}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_cistatic void enic_set_rx_cpu_rmap(struct enic *enic)
159762306a36Sopenharmony_ci{
159862306a36Sopenharmony_ci}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci#endif /* CONFIG_RFS_ACCEL */
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_cistatic int enic_poll_msix_wq(struct napi_struct *napi, int budget)
160362306a36Sopenharmony_ci{
160462306a36Sopenharmony_ci	struct net_device *netdev = napi->dev;
160562306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
160662306a36Sopenharmony_ci	unsigned int wq_index = (napi - &enic->napi[0]) - enic->rq_count;
160762306a36Sopenharmony_ci	struct vnic_wq *wq = &enic->wq[wq_index];
160862306a36Sopenharmony_ci	unsigned int cq;
160962306a36Sopenharmony_ci	unsigned int intr;
161062306a36Sopenharmony_ci	unsigned int wq_work_to_do = ENIC_WQ_NAPI_BUDGET;
161162306a36Sopenharmony_ci	unsigned int wq_work_done;
161262306a36Sopenharmony_ci	unsigned int wq_irq;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	wq_irq = wq->index;
161562306a36Sopenharmony_ci	cq = enic_cq_wq(enic, wq_irq);
161662306a36Sopenharmony_ci	intr = enic_msix_wq_intr(enic, wq_irq);
161762306a36Sopenharmony_ci	wq_work_done = vnic_cq_service(&enic->cq[cq], wq_work_to_do,
161862306a36Sopenharmony_ci				       enic_wq_service, NULL);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	vnic_intr_return_credits(&enic->intr[intr], wq_work_done,
162162306a36Sopenharmony_ci				 0 /* don't unmask intr */,
162262306a36Sopenharmony_ci				 1 /* reset intr timer */);
162362306a36Sopenharmony_ci	if (!wq_work_done) {
162462306a36Sopenharmony_ci		napi_complete(napi);
162562306a36Sopenharmony_ci		vnic_intr_unmask(&enic->intr[intr]);
162662306a36Sopenharmony_ci		return 0;
162762306a36Sopenharmony_ci	}
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci	return budget;
163062306a36Sopenharmony_ci}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_cistatic int enic_poll_msix_rq(struct napi_struct *napi, int budget)
163362306a36Sopenharmony_ci{
163462306a36Sopenharmony_ci	struct net_device *netdev = napi->dev;
163562306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
163662306a36Sopenharmony_ci	unsigned int rq = (napi - &enic->napi[0]);
163762306a36Sopenharmony_ci	unsigned int cq = enic_cq_rq(enic, rq);
163862306a36Sopenharmony_ci	unsigned int intr = enic_msix_rq_intr(enic, rq);
163962306a36Sopenharmony_ci	unsigned int work_to_do = budget;
164062306a36Sopenharmony_ci	unsigned int work_done = 0;
164162306a36Sopenharmony_ci	int err;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	/* Service RQ
164462306a36Sopenharmony_ci	 */
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	if (budget > 0)
164762306a36Sopenharmony_ci		work_done = vnic_cq_service(&enic->cq[cq],
164862306a36Sopenharmony_ci			work_to_do, enic_rq_service, NULL);
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	/* Return intr event credits for this polling
165162306a36Sopenharmony_ci	 * cycle.  An intr event is the completion of a
165262306a36Sopenharmony_ci	 * RQ packet.
165362306a36Sopenharmony_ci	 */
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	if (work_done > 0)
165662306a36Sopenharmony_ci		vnic_intr_return_credits(&enic->intr[intr],
165762306a36Sopenharmony_ci			work_done,
165862306a36Sopenharmony_ci			0 /* don't unmask intr */,
165962306a36Sopenharmony_ci			0 /* don't reset intr timer */);
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	err = vnic_rq_fill(&enic->rq[rq], enic_rq_alloc_buf);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	/* Buffer allocation failed. Stay in polling mode
166462306a36Sopenharmony_ci	 * so we can try to fill the ring again.
166562306a36Sopenharmony_ci	 */
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (err)
166862306a36Sopenharmony_ci		work_done = work_to_do;
166962306a36Sopenharmony_ci	if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
167062306a36Sopenharmony_ci		/* Call the function which refreshes the intr coalescing timer
167162306a36Sopenharmony_ci		 * value based on the traffic.
167262306a36Sopenharmony_ci		 */
167362306a36Sopenharmony_ci		enic_calc_int_moderation(enic, &enic->rq[rq]);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	if ((work_done < budget) && napi_complete_done(napi, work_done)) {
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci		/* Some work done, but not enough to stay in polling,
167862306a36Sopenharmony_ci		 * exit polling
167962306a36Sopenharmony_ci		 */
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci		if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce)
168262306a36Sopenharmony_ci			enic_set_int_moderation(enic, &enic->rq[rq]);
168362306a36Sopenharmony_ci		vnic_intr_unmask(&enic->intr[intr]);
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	return work_done;
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_cistatic void enic_notify_timer(struct timer_list *t)
169062306a36Sopenharmony_ci{
169162306a36Sopenharmony_ci	struct enic *enic = from_timer(enic, t, notify_timer);
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	enic_notify_check(enic);
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	mod_timer(&enic->notify_timer,
169662306a36Sopenharmony_ci		round_jiffies(jiffies + ENIC_NOTIFY_TIMER_PERIOD));
169762306a36Sopenharmony_ci}
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_cistatic void enic_free_intr(struct enic *enic)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	struct net_device *netdev = enic->netdev;
170262306a36Sopenharmony_ci	unsigned int i;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	enic_free_rx_cpu_rmap(enic);
170562306a36Sopenharmony_ci	switch (vnic_dev_get_intr_mode(enic->vdev)) {
170662306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_INTX:
170762306a36Sopenharmony_ci		free_irq(enic->pdev->irq, netdev);
170862306a36Sopenharmony_ci		break;
170962306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSI:
171062306a36Sopenharmony_ci		free_irq(enic->pdev->irq, enic);
171162306a36Sopenharmony_ci		break;
171262306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSIX:
171362306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(enic->msix); i++)
171462306a36Sopenharmony_ci			if (enic->msix[i].requested)
171562306a36Sopenharmony_ci				free_irq(enic->msix_entry[i].vector,
171662306a36Sopenharmony_ci					enic->msix[i].devid);
171762306a36Sopenharmony_ci		break;
171862306a36Sopenharmony_ci	default:
171962306a36Sopenharmony_ci		break;
172062306a36Sopenharmony_ci	}
172162306a36Sopenharmony_ci}
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_cistatic int enic_request_intr(struct enic *enic)
172462306a36Sopenharmony_ci{
172562306a36Sopenharmony_ci	struct net_device *netdev = enic->netdev;
172662306a36Sopenharmony_ci	unsigned int i, intr;
172762306a36Sopenharmony_ci	int err = 0;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	enic_set_rx_cpu_rmap(enic);
173062306a36Sopenharmony_ci	switch (vnic_dev_get_intr_mode(enic->vdev)) {
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_INTX:
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci		err = request_irq(enic->pdev->irq, enic_isr_legacy,
173562306a36Sopenharmony_ci			IRQF_SHARED, netdev->name, netdev);
173662306a36Sopenharmony_ci		break;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSI:
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci		err = request_irq(enic->pdev->irq, enic_isr_msi,
174162306a36Sopenharmony_ci			0, netdev->name, enic);
174262306a36Sopenharmony_ci		break;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSIX:
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci		for (i = 0; i < enic->rq_count; i++) {
174762306a36Sopenharmony_ci			intr = enic_msix_rq_intr(enic, i);
174862306a36Sopenharmony_ci			snprintf(enic->msix[intr].devname,
174962306a36Sopenharmony_ci				sizeof(enic->msix[intr].devname),
175062306a36Sopenharmony_ci				"%s-rx-%u", netdev->name, i);
175162306a36Sopenharmony_ci			enic->msix[intr].isr = enic_isr_msix;
175262306a36Sopenharmony_ci			enic->msix[intr].devid = &enic->napi[i];
175362306a36Sopenharmony_ci		}
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci		for (i = 0; i < enic->wq_count; i++) {
175662306a36Sopenharmony_ci			int wq = enic_cq_wq(enic, i);
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci			intr = enic_msix_wq_intr(enic, i);
175962306a36Sopenharmony_ci			snprintf(enic->msix[intr].devname,
176062306a36Sopenharmony_ci				sizeof(enic->msix[intr].devname),
176162306a36Sopenharmony_ci				"%s-tx-%u", netdev->name, i);
176262306a36Sopenharmony_ci			enic->msix[intr].isr = enic_isr_msix;
176362306a36Sopenharmony_ci			enic->msix[intr].devid = &enic->napi[wq];
176462306a36Sopenharmony_ci		}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci		intr = enic_msix_err_intr(enic);
176762306a36Sopenharmony_ci		snprintf(enic->msix[intr].devname,
176862306a36Sopenharmony_ci			sizeof(enic->msix[intr].devname),
176962306a36Sopenharmony_ci			"%s-err", netdev->name);
177062306a36Sopenharmony_ci		enic->msix[intr].isr = enic_isr_msix_err;
177162306a36Sopenharmony_ci		enic->msix[intr].devid = enic;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci		intr = enic_msix_notify_intr(enic);
177462306a36Sopenharmony_ci		snprintf(enic->msix[intr].devname,
177562306a36Sopenharmony_ci			sizeof(enic->msix[intr].devname),
177662306a36Sopenharmony_ci			"%s-notify", netdev->name);
177762306a36Sopenharmony_ci		enic->msix[intr].isr = enic_isr_msix_notify;
177862306a36Sopenharmony_ci		enic->msix[intr].devid = enic;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(enic->msix); i++)
178162306a36Sopenharmony_ci			enic->msix[i].requested = 0;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci		for (i = 0; i < enic->intr_count; i++) {
178462306a36Sopenharmony_ci			err = request_irq(enic->msix_entry[i].vector,
178562306a36Sopenharmony_ci				enic->msix[i].isr, 0,
178662306a36Sopenharmony_ci				enic->msix[i].devname,
178762306a36Sopenharmony_ci				enic->msix[i].devid);
178862306a36Sopenharmony_ci			if (err) {
178962306a36Sopenharmony_ci				enic_free_intr(enic);
179062306a36Sopenharmony_ci				break;
179162306a36Sopenharmony_ci			}
179262306a36Sopenharmony_ci			enic->msix[i].requested = 1;
179362306a36Sopenharmony_ci		}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci		break;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	default:
179862306a36Sopenharmony_ci		break;
179962306a36Sopenharmony_ci	}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	return err;
180262306a36Sopenharmony_ci}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_cistatic void enic_synchronize_irqs(struct enic *enic)
180562306a36Sopenharmony_ci{
180662306a36Sopenharmony_ci	unsigned int i;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	switch (vnic_dev_get_intr_mode(enic->vdev)) {
180962306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_INTX:
181062306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSI:
181162306a36Sopenharmony_ci		synchronize_irq(enic->pdev->irq);
181262306a36Sopenharmony_ci		break;
181362306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSIX:
181462306a36Sopenharmony_ci		for (i = 0; i < enic->intr_count; i++)
181562306a36Sopenharmony_ci			synchronize_irq(enic->msix_entry[i].vector);
181662306a36Sopenharmony_ci		break;
181762306a36Sopenharmony_ci	default:
181862306a36Sopenharmony_ci		break;
181962306a36Sopenharmony_ci	}
182062306a36Sopenharmony_ci}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_cistatic void enic_set_rx_coal_setting(struct enic *enic)
182362306a36Sopenharmony_ci{
182462306a36Sopenharmony_ci	unsigned int speed;
182562306a36Sopenharmony_ci	int index = -1;
182662306a36Sopenharmony_ci	struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	/* 1. Read the link speed from fw
182962306a36Sopenharmony_ci	 * 2. Pick the default range for the speed
183062306a36Sopenharmony_ci	 * 3. Update it in enic->rx_coalesce_setting
183162306a36Sopenharmony_ci	 */
183262306a36Sopenharmony_ci	speed = vnic_dev_port_speed(enic->vdev);
183362306a36Sopenharmony_ci	if (ENIC_LINK_SPEED_10G < speed)
183462306a36Sopenharmony_ci		index = ENIC_LINK_40G_INDEX;
183562306a36Sopenharmony_ci	else if (ENIC_LINK_SPEED_4G < speed)
183662306a36Sopenharmony_ci		index = ENIC_LINK_10G_INDEX;
183762306a36Sopenharmony_ci	else
183862306a36Sopenharmony_ci		index = ENIC_LINK_4G_INDEX;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	rx_coal->small_pkt_range_start = mod_range[index].small_pkt_range_start;
184162306a36Sopenharmony_ci	rx_coal->large_pkt_range_start = mod_range[index].large_pkt_range_start;
184262306a36Sopenharmony_ci	rx_coal->range_end = ENIC_RX_COALESCE_RANGE_END;
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	/* Start with the value provided by UCSM */
184562306a36Sopenharmony_ci	for (index = 0; index < enic->rq_count; index++)
184662306a36Sopenharmony_ci		enic->cq[index].cur_rx_coal_timeval =
184762306a36Sopenharmony_ci				enic->config.intr_timer_usec;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	rx_coal->use_adaptive_rx_coalesce = 1;
185062306a36Sopenharmony_ci}
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_cistatic int enic_dev_notify_set(struct enic *enic)
185362306a36Sopenharmony_ci{
185462306a36Sopenharmony_ci	int err;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	spin_lock_bh(&enic->devcmd_lock);
185762306a36Sopenharmony_ci	switch (vnic_dev_get_intr_mode(enic->vdev)) {
185862306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_INTX:
185962306a36Sopenharmony_ci		err = vnic_dev_notify_set(enic->vdev, ENIC_LEGACY_NOTIFY_INTR);
186062306a36Sopenharmony_ci		break;
186162306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSIX:
186262306a36Sopenharmony_ci		err = vnic_dev_notify_set(enic->vdev,
186362306a36Sopenharmony_ci			enic_msix_notify_intr(enic));
186462306a36Sopenharmony_ci		break;
186562306a36Sopenharmony_ci	default:
186662306a36Sopenharmony_ci		err = vnic_dev_notify_set(enic->vdev, -1 /* no intr */);
186762306a36Sopenharmony_ci		break;
186862306a36Sopenharmony_ci	}
186962306a36Sopenharmony_ci	spin_unlock_bh(&enic->devcmd_lock);
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	return err;
187262306a36Sopenharmony_ci}
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_cistatic void enic_notify_timer_start(struct enic *enic)
187562306a36Sopenharmony_ci{
187662306a36Sopenharmony_ci	switch (vnic_dev_get_intr_mode(enic->vdev)) {
187762306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSI:
187862306a36Sopenharmony_ci		mod_timer(&enic->notify_timer, jiffies);
187962306a36Sopenharmony_ci		break;
188062306a36Sopenharmony_ci	default:
188162306a36Sopenharmony_ci		/* Using intr for notification for INTx/MSI-X */
188262306a36Sopenharmony_ci		break;
188362306a36Sopenharmony_ci	}
188462306a36Sopenharmony_ci}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci/* rtnl lock is held, process context */
188762306a36Sopenharmony_cistatic int enic_open(struct net_device *netdev)
188862306a36Sopenharmony_ci{
188962306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
189062306a36Sopenharmony_ci	unsigned int i;
189162306a36Sopenharmony_ci	int err, ret;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	err = enic_request_intr(enic);
189462306a36Sopenharmony_ci	if (err) {
189562306a36Sopenharmony_ci		netdev_err(netdev, "Unable to request irq.\n");
189662306a36Sopenharmony_ci		return err;
189762306a36Sopenharmony_ci	}
189862306a36Sopenharmony_ci	enic_init_affinity_hint(enic);
189962306a36Sopenharmony_ci	enic_set_affinity_hint(enic);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	err = enic_dev_notify_set(enic);
190262306a36Sopenharmony_ci	if (err) {
190362306a36Sopenharmony_ci		netdev_err(netdev,
190462306a36Sopenharmony_ci			"Failed to alloc notify buffer, aborting.\n");
190562306a36Sopenharmony_ci		goto err_out_free_intr;
190662306a36Sopenharmony_ci	}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	for (i = 0; i < enic->rq_count; i++) {
190962306a36Sopenharmony_ci		/* enable rq before updating rq desc */
191062306a36Sopenharmony_ci		vnic_rq_enable(&enic->rq[i]);
191162306a36Sopenharmony_ci		vnic_rq_fill(&enic->rq[i], enic_rq_alloc_buf);
191262306a36Sopenharmony_ci		/* Need at least one buffer on ring to get going */
191362306a36Sopenharmony_ci		if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
191462306a36Sopenharmony_ci			netdev_err(netdev, "Unable to alloc receive buffers\n");
191562306a36Sopenharmony_ci			err = -ENOMEM;
191662306a36Sopenharmony_ci			goto err_out_free_rq;
191762306a36Sopenharmony_ci		}
191862306a36Sopenharmony_ci	}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	for (i = 0; i < enic->wq_count; i++)
192162306a36Sopenharmony_ci		vnic_wq_enable(&enic->wq[i]);
192262306a36Sopenharmony_ci
192362306a36Sopenharmony_ci	if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic))
192462306a36Sopenharmony_ci		enic_dev_add_station_addr(enic);
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	enic_set_rx_mode(netdev);
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	netif_tx_wake_all_queues(netdev);
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	for (i = 0; i < enic->rq_count; i++)
193162306a36Sopenharmony_ci		napi_enable(&enic->napi[i]);
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_ci	if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX)
193462306a36Sopenharmony_ci		for (i = 0; i < enic->wq_count; i++)
193562306a36Sopenharmony_ci			napi_enable(&enic->napi[enic_cq_wq(enic, i)]);
193662306a36Sopenharmony_ci	enic_dev_enable(enic);
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	for (i = 0; i < enic->intr_count; i++)
193962306a36Sopenharmony_ci		vnic_intr_unmask(&enic->intr[i]);
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	enic_notify_timer_start(enic);
194262306a36Sopenharmony_ci	enic_rfs_timer_start(enic);
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	return 0;
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_cierr_out_free_rq:
194762306a36Sopenharmony_ci	for (i = 0; i < enic->rq_count; i++) {
194862306a36Sopenharmony_ci		ret = vnic_rq_disable(&enic->rq[i]);
194962306a36Sopenharmony_ci		if (!ret)
195062306a36Sopenharmony_ci			vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
195162306a36Sopenharmony_ci	}
195262306a36Sopenharmony_ci	enic_dev_notify_unset(enic);
195362306a36Sopenharmony_cierr_out_free_intr:
195462306a36Sopenharmony_ci	enic_unset_affinity_hint(enic);
195562306a36Sopenharmony_ci	enic_free_intr(enic);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci	return err;
195862306a36Sopenharmony_ci}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci/* rtnl lock is held, process context */
196162306a36Sopenharmony_cistatic int enic_stop(struct net_device *netdev)
196262306a36Sopenharmony_ci{
196362306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
196462306a36Sopenharmony_ci	unsigned int i;
196562306a36Sopenharmony_ci	int err;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	for (i = 0; i < enic->intr_count; i++) {
196862306a36Sopenharmony_ci		vnic_intr_mask(&enic->intr[i]);
196962306a36Sopenharmony_ci		(void)vnic_intr_masked(&enic->intr[i]); /* flush write */
197062306a36Sopenharmony_ci	}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	enic_synchronize_irqs(enic);
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	del_timer_sync(&enic->notify_timer);
197562306a36Sopenharmony_ci	enic_rfs_flw_tbl_free(enic);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	enic_dev_disable(enic);
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci	for (i = 0; i < enic->rq_count; i++)
198062306a36Sopenharmony_ci		napi_disable(&enic->napi[i]);
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	netif_carrier_off(netdev);
198362306a36Sopenharmony_ci	if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX)
198462306a36Sopenharmony_ci		for (i = 0; i < enic->wq_count; i++)
198562306a36Sopenharmony_ci			napi_disable(&enic->napi[enic_cq_wq(enic, i)]);
198662306a36Sopenharmony_ci	netif_tx_disable(netdev);
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	if (!enic_is_dynamic(enic) && !enic_is_sriov_vf(enic))
198962306a36Sopenharmony_ci		enic_dev_del_station_addr(enic);
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	for (i = 0; i < enic->wq_count; i++) {
199262306a36Sopenharmony_ci		err = vnic_wq_disable(&enic->wq[i]);
199362306a36Sopenharmony_ci		if (err)
199462306a36Sopenharmony_ci			return err;
199562306a36Sopenharmony_ci	}
199662306a36Sopenharmony_ci	for (i = 0; i < enic->rq_count; i++) {
199762306a36Sopenharmony_ci		err = vnic_rq_disable(&enic->rq[i]);
199862306a36Sopenharmony_ci		if (err)
199962306a36Sopenharmony_ci			return err;
200062306a36Sopenharmony_ci	}
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	enic_dev_notify_unset(enic);
200362306a36Sopenharmony_ci	enic_unset_affinity_hint(enic);
200462306a36Sopenharmony_ci	enic_free_intr(enic);
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	for (i = 0; i < enic->wq_count; i++)
200762306a36Sopenharmony_ci		vnic_wq_clean(&enic->wq[i], enic_free_wq_buf);
200862306a36Sopenharmony_ci	for (i = 0; i < enic->rq_count; i++)
200962306a36Sopenharmony_ci		vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
201062306a36Sopenharmony_ci	for (i = 0; i < enic->cq_count; i++)
201162306a36Sopenharmony_ci		vnic_cq_clean(&enic->cq[i]);
201262306a36Sopenharmony_ci	for (i = 0; i < enic->intr_count; i++)
201362306a36Sopenharmony_ci		vnic_intr_clean(&enic->intr[i]);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	return 0;
201662306a36Sopenharmony_ci}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_cistatic int _enic_change_mtu(struct net_device *netdev, int new_mtu)
201962306a36Sopenharmony_ci{
202062306a36Sopenharmony_ci	bool running = netif_running(netdev);
202162306a36Sopenharmony_ci	int err = 0;
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	ASSERT_RTNL();
202462306a36Sopenharmony_ci	if (running) {
202562306a36Sopenharmony_ci		err = enic_stop(netdev);
202662306a36Sopenharmony_ci		if (err)
202762306a36Sopenharmony_ci			return err;
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	netdev->mtu = new_mtu;
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci	if (running) {
203362306a36Sopenharmony_ci		err = enic_open(netdev);
203462306a36Sopenharmony_ci		if (err)
203562306a36Sopenharmony_ci			return err;
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	return 0;
203962306a36Sopenharmony_ci}
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_cistatic int enic_change_mtu(struct net_device *netdev, int new_mtu)
204262306a36Sopenharmony_ci{
204362306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic))
204662306a36Sopenharmony_ci		return -EOPNOTSUPP;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	if (netdev->mtu > enic->port_mtu)
204962306a36Sopenharmony_ci		netdev_warn(netdev,
205062306a36Sopenharmony_ci			    "interface MTU (%d) set higher than port MTU (%d)\n",
205162306a36Sopenharmony_ci			    netdev->mtu, enic->port_mtu);
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	return _enic_change_mtu(netdev, new_mtu);
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_cistatic void enic_change_mtu_work(struct work_struct *work)
205762306a36Sopenharmony_ci{
205862306a36Sopenharmony_ci	struct enic *enic = container_of(work, struct enic, change_mtu_work);
205962306a36Sopenharmony_ci	struct net_device *netdev = enic->netdev;
206062306a36Sopenharmony_ci	int new_mtu = vnic_dev_mtu(enic->vdev);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	rtnl_lock();
206362306a36Sopenharmony_ci	(void)_enic_change_mtu(netdev, new_mtu);
206462306a36Sopenharmony_ci	rtnl_unlock();
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	netdev_info(netdev, "interface MTU set as %d\n", netdev->mtu);
206762306a36Sopenharmony_ci}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
207062306a36Sopenharmony_cistatic void enic_poll_controller(struct net_device *netdev)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	struct enic *enic = netdev_priv(netdev);
207362306a36Sopenharmony_ci	struct vnic_dev *vdev = enic->vdev;
207462306a36Sopenharmony_ci	unsigned int i, intr;
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci	switch (vnic_dev_get_intr_mode(vdev)) {
207762306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSIX:
207862306a36Sopenharmony_ci		for (i = 0; i < enic->rq_count; i++) {
207962306a36Sopenharmony_ci			intr = enic_msix_rq_intr(enic, i);
208062306a36Sopenharmony_ci			enic_isr_msix(enic->msix_entry[intr].vector,
208162306a36Sopenharmony_ci				      &enic->napi[i]);
208262306a36Sopenharmony_ci		}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci		for (i = 0; i < enic->wq_count; i++) {
208562306a36Sopenharmony_ci			intr = enic_msix_wq_intr(enic, i);
208662306a36Sopenharmony_ci			enic_isr_msix(enic->msix_entry[intr].vector,
208762306a36Sopenharmony_ci				      &enic->napi[enic_cq_wq(enic, i)]);
208862306a36Sopenharmony_ci		}
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci		break;
209162306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSI:
209262306a36Sopenharmony_ci		enic_isr_msi(enic->pdev->irq, enic);
209362306a36Sopenharmony_ci		break;
209462306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_INTX:
209562306a36Sopenharmony_ci		enic_isr_legacy(enic->pdev->irq, netdev);
209662306a36Sopenharmony_ci		break;
209762306a36Sopenharmony_ci	default:
209862306a36Sopenharmony_ci		break;
209962306a36Sopenharmony_ci	}
210062306a36Sopenharmony_ci}
210162306a36Sopenharmony_ci#endif
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_cistatic int enic_dev_wait(struct vnic_dev *vdev,
210462306a36Sopenharmony_ci	int (*start)(struct vnic_dev *, int),
210562306a36Sopenharmony_ci	int (*finished)(struct vnic_dev *, int *),
210662306a36Sopenharmony_ci	int arg)
210762306a36Sopenharmony_ci{
210862306a36Sopenharmony_ci	unsigned long time;
210962306a36Sopenharmony_ci	int done;
211062306a36Sopenharmony_ci	int err;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	err = start(vdev, arg);
211362306a36Sopenharmony_ci	if (err)
211462306a36Sopenharmony_ci		return err;
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci	/* Wait for func to complete...2 seconds max
211762306a36Sopenharmony_ci	 */
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	time = jiffies + (HZ * 2);
212062306a36Sopenharmony_ci	do {
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci		err = finished(vdev, &done);
212362306a36Sopenharmony_ci		if (err)
212462306a36Sopenharmony_ci			return err;
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci		if (done)
212762306a36Sopenharmony_ci			return 0;
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci		schedule_timeout_uninterruptible(HZ / 10);
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	} while (time_after(time, jiffies));
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	return -ETIMEDOUT;
213462306a36Sopenharmony_ci}
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_cistatic int enic_dev_open(struct enic *enic)
213762306a36Sopenharmony_ci{
213862306a36Sopenharmony_ci	int err;
213962306a36Sopenharmony_ci	u32 flags = CMD_OPENF_IG_DESCCACHE;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	err = enic_dev_wait(enic->vdev, vnic_dev_open,
214262306a36Sopenharmony_ci		vnic_dev_open_done, flags);
214362306a36Sopenharmony_ci	if (err)
214462306a36Sopenharmony_ci		dev_err(enic_get_dev(enic), "vNIC device open failed, err %d\n",
214562306a36Sopenharmony_ci			err);
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	return err;
214862306a36Sopenharmony_ci}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_cistatic int enic_dev_soft_reset(struct enic *enic)
215162306a36Sopenharmony_ci{
215262306a36Sopenharmony_ci	int err;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	err = enic_dev_wait(enic->vdev, vnic_dev_soft_reset,
215562306a36Sopenharmony_ci			    vnic_dev_soft_reset_done, 0);
215662306a36Sopenharmony_ci	if (err)
215762306a36Sopenharmony_ci		netdev_err(enic->netdev, "vNIC soft reset failed, err %d\n",
215862306a36Sopenharmony_ci			   err);
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	return err;
216162306a36Sopenharmony_ci}
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_cistatic int enic_dev_hang_reset(struct enic *enic)
216462306a36Sopenharmony_ci{
216562306a36Sopenharmony_ci	int err;
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	err = enic_dev_wait(enic->vdev, vnic_dev_hang_reset,
216862306a36Sopenharmony_ci		vnic_dev_hang_reset_done, 0);
216962306a36Sopenharmony_ci	if (err)
217062306a36Sopenharmony_ci		netdev_err(enic->netdev, "vNIC hang reset failed, err %d\n",
217162306a36Sopenharmony_ci			err);
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	return err;
217462306a36Sopenharmony_ci}
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ciint __enic_set_rsskey(struct enic *enic)
217762306a36Sopenharmony_ci{
217862306a36Sopenharmony_ci	union vnic_rss_key *rss_key_buf_va;
217962306a36Sopenharmony_ci	dma_addr_t rss_key_buf_pa;
218062306a36Sopenharmony_ci	int i, kidx, bidx, err;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	rss_key_buf_va = dma_alloc_coherent(&enic->pdev->dev,
218362306a36Sopenharmony_ci					    sizeof(union vnic_rss_key),
218462306a36Sopenharmony_ci					    &rss_key_buf_pa, GFP_ATOMIC);
218562306a36Sopenharmony_ci	if (!rss_key_buf_va)
218662306a36Sopenharmony_ci		return -ENOMEM;
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	for (i = 0; i < ENIC_RSS_LEN; i++) {
218962306a36Sopenharmony_ci		kidx = i / ENIC_RSS_BYTES_PER_KEY;
219062306a36Sopenharmony_ci		bidx = i % ENIC_RSS_BYTES_PER_KEY;
219162306a36Sopenharmony_ci		rss_key_buf_va->key[kidx].b[bidx] = enic->rss_key[i];
219262306a36Sopenharmony_ci	}
219362306a36Sopenharmony_ci	spin_lock_bh(&enic->devcmd_lock);
219462306a36Sopenharmony_ci	err = enic_set_rss_key(enic,
219562306a36Sopenharmony_ci		rss_key_buf_pa,
219662306a36Sopenharmony_ci		sizeof(union vnic_rss_key));
219762306a36Sopenharmony_ci	spin_unlock_bh(&enic->devcmd_lock);
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	dma_free_coherent(&enic->pdev->dev, sizeof(union vnic_rss_key),
220062306a36Sopenharmony_ci			  rss_key_buf_va, rss_key_buf_pa);
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	return err;
220362306a36Sopenharmony_ci}
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_cistatic int enic_set_rsskey(struct enic *enic)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	netdev_rss_key_fill(enic->rss_key, ENIC_RSS_LEN);
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	return __enic_set_rsskey(enic);
221062306a36Sopenharmony_ci}
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_cistatic int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
221362306a36Sopenharmony_ci{
221462306a36Sopenharmony_ci	dma_addr_t rss_cpu_buf_pa;
221562306a36Sopenharmony_ci	union vnic_rss_cpu *rss_cpu_buf_va = NULL;
221662306a36Sopenharmony_ci	unsigned int i;
221762306a36Sopenharmony_ci	int err;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	rss_cpu_buf_va = dma_alloc_coherent(&enic->pdev->dev,
222062306a36Sopenharmony_ci					    sizeof(union vnic_rss_cpu),
222162306a36Sopenharmony_ci					    &rss_cpu_buf_pa, GFP_ATOMIC);
222262306a36Sopenharmony_ci	if (!rss_cpu_buf_va)
222362306a36Sopenharmony_ci		return -ENOMEM;
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	for (i = 0; i < (1 << rss_hash_bits); i++)
222662306a36Sopenharmony_ci		(*rss_cpu_buf_va).cpu[i/4].b[i%4] = i % enic->rq_count;
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	spin_lock_bh(&enic->devcmd_lock);
222962306a36Sopenharmony_ci	err = enic_set_rss_cpu(enic,
223062306a36Sopenharmony_ci		rss_cpu_buf_pa,
223162306a36Sopenharmony_ci		sizeof(union vnic_rss_cpu));
223262306a36Sopenharmony_ci	spin_unlock_bh(&enic->devcmd_lock);
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	dma_free_coherent(&enic->pdev->dev, sizeof(union vnic_rss_cpu),
223562306a36Sopenharmony_ci			  rss_cpu_buf_va, rss_cpu_buf_pa);
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	return err;
223862306a36Sopenharmony_ci}
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_cistatic int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu,
224162306a36Sopenharmony_ci	u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	const u8 tso_ipid_split_en = 0;
224462306a36Sopenharmony_ci	const u8 ig_vlan_strip_en = 1;
224562306a36Sopenharmony_ci	int err;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	/* Enable VLAN tag stripping.
224862306a36Sopenharmony_ci	*/
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	spin_lock_bh(&enic->devcmd_lock);
225162306a36Sopenharmony_ci	err = enic_set_nic_cfg(enic,
225262306a36Sopenharmony_ci		rss_default_cpu, rss_hash_type,
225362306a36Sopenharmony_ci		rss_hash_bits, rss_base_cpu,
225462306a36Sopenharmony_ci		rss_enable, tso_ipid_split_en,
225562306a36Sopenharmony_ci		ig_vlan_strip_en);
225662306a36Sopenharmony_ci	spin_unlock_bh(&enic->devcmd_lock);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	return err;
225962306a36Sopenharmony_ci}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_cistatic int enic_set_rss_nic_cfg(struct enic *enic)
226262306a36Sopenharmony_ci{
226362306a36Sopenharmony_ci	struct device *dev = enic_get_dev(enic);
226462306a36Sopenharmony_ci	const u8 rss_default_cpu = 0;
226562306a36Sopenharmony_ci	const u8 rss_hash_bits = 7;
226662306a36Sopenharmony_ci	const u8 rss_base_cpu = 0;
226762306a36Sopenharmony_ci	u8 rss_hash_type;
226862306a36Sopenharmony_ci	int res;
226962306a36Sopenharmony_ci	u8 rss_enable = ENIC_SETTING(enic, RSS) && (enic->rq_count > 1);
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	spin_lock_bh(&enic->devcmd_lock);
227262306a36Sopenharmony_ci	res = vnic_dev_capable_rss_hash_type(enic->vdev, &rss_hash_type);
227362306a36Sopenharmony_ci	spin_unlock_bh(&enic->devcmd_lock);
227462306a36Sopenharmony_ci	if (res) {
227562306a36Sopenharmony_ci		/* defaults for old adapters
227662306a36Sopenharmony_ci		 */
227762306a36Sopenharmony_ci		rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4	|
227862306a36Sopenharmony_ci				NIC_CFG_RSS_HASH_TYPE_TCP_IPV4	|
227962306a36Sopenharmony_ci				NIC_CFG_RSS_HASH_TYPE_IPV6	|
228062306a36Sopenharmony_ci				NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
228162306a36Sopenharmony_ci	}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	if (rss_enable) {
228462306a36Sopenharmony_ci		if (!enic_set_rsskey(enic)) {
228562306a36Sopenharmony_ci			if (enic_set_rsscpu(enic, rss_hash_bits)) {
228662306a36Sopenharmony_ci				rss_enable = 0;
228762306a36Sopenharmony_ci				dev_warn(dev, "RSS disabled, "
228862306a36Sopenharmony_ci					"Failed to set RSS cpu indirection table.");
228962306a36Sopenharmony_ci			}
229062306a36Sopenharmony_ci		} else {
229162306a36Sopenharmony_ci			rss_enable = 0;
229262306a36Sopenharmony_ci			dev_warn(dev, "RSS disabled, Failed to set RSS key.\n");
229362306a36Sopenharmony_ci		}
229462306a36Sopenharmony_ci	}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	return enic_set_niccfg(enic, rss_default_cpu, rss_hash_type,
229762306a36Sopenharmony_ci		rss_hash_bits, rss_base_cpu, rss_enable);
229862306a36Sopenharmony_ci}
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_cistatic void enic_set_api_busy(struct enic *enic, bool busy)
230162306a36Sopenharmony_ci{
230262306a36Sopenharmony_ci	spin_lock(&enic->enic_api_lock);
230362306a36Sopenharmony_ci	enic->enic_api_busy = busy;
230462306a36Sopenharmony_ci	spin_unlock(&enic->enic_api_lock);
230562306a36Sopenharmony_ci}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_cistatic void enic_reset(struct work_struct *work)
230862306a36Sopenharmony_ci{
230962306a36Sopenharmony_ci	struct enic *enic = container_of(work, struct enic, reset);
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	if (!netif_running(enic->netdev))
231262306a36Sopenharmony_ci		return;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	rtnl_lock();
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	/* Stop any activity from infiniband */
231762306a36Sopenharmony_ci	enic_set_api_busy(enic, true);
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	enic_stop(enic->netdev);
232062306a36Sopenharmony_ci	enic_dev_soft_reset(enic);
232162306a36Sopenharmony_ci	enic_reset_addr_lists(enic);
232262306a36Sopenharmony_ci	enic_init_vnic_resources(enic);
232362306a36Sopenharmony_ci	enic_set_rss_nic_cfg(enic);
232462306a36Sopenharmony_ci	enic_dev_set_ig_vlan_rewrite_mode(enic);
232562306a36Sopenharmony_ci	enic_open(enic->netdev);
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	/* Allow infiniband to fiddle with the device again */
232862306a36Sopenharmony_ci	enic_set_api_busy(enic, false);
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	call_netdevice_notifiers(NETDEV_REBOOT, enic->netdev);
233162306a36Sopenharmony_ci
233262306a36Sopenharmony_ci	rtnl_unlock();
233362306a36Sopenharmony_ci}
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_cistatic void enic_tx_hang_reset(struct work_struct *work)
233662306a36Sopenharmony_ci{
233762306a36Sopenharmony_ci	struct enic *enic = container_of(work, struct enic, tx_hang_reset);
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	rtnl_lock();
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	/* Stop any activity from infiniband */
234262306a36Sopenharmony_ci	enic_set_api_busy(enic, true);
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	enic_dev_hang_notify(enic);
234562306a36Sopenharmony_ci	enic_stop(enic->netdev);
234662306a36Sopenharmony_ci	enic_dev_hang_reset(enic);
234762306a36Sopenharmony_ci	enic_reset_addr_lists(enic);
234862306a36Sopenharmony_ci	enic_init_vnic_resources(enic);
234962306a36Sopenharmony_ci	enic_set_rss_nic_cfg(enic);
235062306a36Sopenharmony_ci	enic_dev_set_ig_vlan_rewrite_mode(enic);
235162306a36Sopenharmony_ci	enic_open(enic->netdev);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	/* Allow infiniband to fiddle with the device again */
235462306a36Sopenharmony_ci	enic_set_api_busy(enic, false);
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	call_netdevice_notifiers(NETDEV_REBOOT, enic->netdev);
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	rtnl_unlock();
235962306a36Sopenharmony_ci}
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_cistatic int enic_set_intr_mode(struct enic *enic)
236262306a36Sopenharmony_ci{
236362306a36Sopenharmony_ci	unsigned int n = min_t(unsigned int, enic->rq_count, ENIC_RQ_MAX);
236462306a36Sopenharmony_ci	unsigned int m = min_t(unsigned int, enic->wq_count, ENIC_WQ_MAX);
236562306a36Sopenharmony_ci	unsigned int i;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	/* Set interrupt mode (INTx, MSI, MSI-X) depending
236862306a36Sopenharmony_ci	 * on system capabilities.
236962306a36Sopenharmony_ci	 *
237062306a36Sopenharmony_ci	 * Try MSI-X first
237162306a36Sopenharmony_ci	 *
237262306a36Sopenharmony_ci	 * We need n RQs, m WQs, n+m CQs, and n+m+2 INTRs
237362306a36Sopenharmony_ci	 * (the second to last INTR is used for WQ/RQ errors)
237462306a36Sopenharmony_ci	 * (the last INTR is used for notifications)
237562306a36Sopenharmony_ci	 */
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	BUG_ON(ARRAY_SIZE(enic->msix_entry) < n + m + 2);
237862306a36Sopenharmony_ci	for (i = 0; i < n + m + 2; i++)
237962306a36Sopenharmony_ci		enic->msix_entry[i].entry = i;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	/* Use multiple RQs if RSS is enabled
238262306a36Sopenharmony_ci	 */
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci	if (ENIC_SETTING(enic, RSS) &&
238562306a36Sopenharmony_ci	    enic->config.intr_mode < 1 &&
238662306a36Sopenharmony_ci	    enic->rq_count >= n &&
238762306a36Sopenharmony_ci	    enic->wq_count >= m &&
238862306a36Sopenharmony_ci	    enic->cq_count >= n + m &&
238962306a36Sopenharmony_ci	    enic->intr_count >= n + m + 2) {
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_ci		if (pci_enable_msix_range(enic->pdev, enic->msix_entry,
239262306a36Sopenharmony_ci					  n + m + 2, n + m + 2) > 0) {
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci			enic->rq_count = n;
239562306a36Sopenharmony_ci			enic->wq_count = m;
239662306a36Sopenharmony_ci			enic->cq_count = n + m;
239762306a36Sopenharmony_ci			enic->intr_count = n + m + 2;
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci			vnic_dev_set_intr_mode(enic->vdev,
240062306a36Sopenharmony_ci				VNIC_DEV_INTR_MODE_MSIX);
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci			return 0;
240362306a36Sopenharmony_ci		}
240462306a36Sopenharmony_ci	}
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	if (enic->config.intr_mode < 1 &&
240762306a36Sopenharmony_ci	    enic->rq_count >= 1 &&
240862306a36Sopenharmony_ci	    enic->wq_count >= m &&
240962306a36Sopenharmony_ci	    enic->cq_count >= 1 + m &&
241062306a36Sopenharmony_ci	    enic->intr_count >= 1 + m + 2) {
241162306a36Sopenharmony_ci		if (pci_enable_msix_range(enic->pdev, enic->msix_entry,
241262306a36Sopenharmony_ci					  1 + m + 2, 1 + m + 2) > 0) {
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci			enic->rq_count = 1;
241562306a36Sopenharmony_ci			enic->wq_count = m;
241662306a36Sopenharmony_ci			enic->cq_count = 1 + m;
241762306a36Sopenharmony_ci			enic->intr_count = 1 + m + 2;
241862306a36Sopenharmony_ci
241962306a36Sopenharmony_ci			vnic_dev_set_intr_mode(enic->vdev,
242062306a36Sopenharmony_ci				VNIC_DEV_INTR_MODE_MSIX);
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci			return 0;
242362306a36Sopenharmony_ci		}
242462306a36Sopenharmony_ci	}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci	/* Next try MSI
242762306a36Sopenharmony_ci	 *
242862306a36Sopenharmony_ci	 * We need 1 RQ, 1 WQ, 2 CQs, and 1 INTR
242962306a36Sopenharmony_ci	 */
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci	if (enic->config.intr_mode < 2 &&
243262306a36Sopenharmony_ci	    enic->rq_count >= 1 &&
243362306a36Sopenharmony_ci	    enic->wq_count >= 1 &&
243462306a36Sopenharmony_ci	    enic->cq_count >= 2 &&
243562306a36Sopenharmony_ci	    enic->intr_count >= 1 &&
243662306a36Sopenharmony_ci	    !pci_enable_msi(enic->pdev)) {
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci		enic->rq_count = 1;
243962306a36Sopenharmony_ci		enic->wq_count = 1;
244062306a36Sopenharmony_ci		enic->cq_count = 2;
244162306a36Sopenharmony_ci		enic->intr_count = 1;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci		vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_MSI);
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci		return 0;
244662306a36Sopenharmony_ci	}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	/* Next try INTx
244962306a36Sopenharmony_ci	 *
245062306a36Sopenharmony_ci	 * We need 1 RQ, 1 WQ, 2 CQs, and 3 INTRs
245162306a36Sopenharmony_ci	 * (the first INTR is used for WQ/RQ)
245262306a36Sopenharmony_ci	 * (the second INTR is used for WQ/RQ errors)
245362306a36Sopenharmony_ci	 * (the last INTR is used for notifications)
245462306a36Sopenharmony_ci	 */
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci	if (enic->config.intr_mode < 3 &&
245762306a36Sopenharmony_ci	    enic->rq_count >= 1 &&
245862306a36Sopenharmony_ci	    enic->wq_count >= 1 &&
245962306a36Sopenharmony_ci	    enic->cq_count >= 2 &&
246062306a36Sopenharmony_ci	    enic->intr_count >= 3) {
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci		enic->rq_count = 1;
246362306a36Sopenharmony_ci		enic->wq_count = 1;
246462306a36Sopenharmony_ci		enic->cq_count = 2;
246562306a36Sopenharmony_ci		enic->intr_count = 3;
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci		vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_INTX);
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci		return 0;
247062306a36Sopenharmony_ci	}
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	return -EINVAL;
247562306a36Sopenharmony_ci}
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_cistatic void enic_clear_intr_mode(struct enic *enic)
247862306a36Sopenharmony_ci{
247962306a36Sopenharmony_ci	switch (vnic_dev_get_intr_mode(enic->vdev)) {
248062306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSIX:
248162306a36Sopenharmony_ci		pci_disable_msix(enic->pdev);
248262306a36Sopenharmony_ci		break;
248362306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSI:
248462306a36Sopenharmony_ci		pci_disable_msi(enic->pdev);
248562306a36Sopenharmony_ci		break;
248662306a36Sopenharmony_ci	default:
248762306a36Sopenharmony_ci		break;
248862306a36Sopenharmony_ci	}
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
249162306a36Sopenharmony_ci}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_cistatic const struct net_device_ops enic_netdev_dynamic_ops = {
249462306a36Sopenharmony_ci	.ndo_open		= enic_open,
249562306a36Sopenharmony_ci	.ndo_stop		= enic_stop,
249662306a36Sopenharmony_ci	.ndo_start_xmit		= enic_hard_start_xmit,
249762306a36Sopenharmony_ci	.ndo_get_stats64	= enic_get_stats,
249862306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
249962306a36Sopenharmony_ci	.ndo_set_rx_mode	= enic_set_rx_mode,
250062306a36Sopenharmony_ci	.ndo_set_mac_address	= enic_set_mac_address_dynamic,
250162306a36Sopenharmony_ci	.ndo_change_mtu		= enic_change_mtu,
250262306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid	= enic_vlan_rx_add_vid,
250362306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= enic_vlan_rx_kill_vid,
250462306a36Sopenharmony_ci	.ndo_tx_timeout		= enic_tx_timeout,
250562306a36Sopenharmony_ci	.ndo_set_vf_port	= enic_set_vf_port,
250662306a36Sopenharmony_ci	.ndo_get_vf_port	= enic_get_vf_port,
250762306a36Sopenharmony_ci	.ndo_set_vf_mac		= enic_set_vf_mac,
250862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
250962306a36Sopenharmony_ci	.ndo_poll_controller	= enic_poll_controller,
251062306a36Sopenharmony_ci#endif
251162306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
251262306a36Sopenharmony_ci	.ndo_rx_flow_steer	= enic_rx_flow_steer,
251362306a36Sopenharmony_ci#endif
251462306a36Sopenharmony_ci	.ndo_features_check	= enic_features_check,
251562306a36Sopenharmony_ci};
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_cistatic const struct net_device_ops enic_netdev_ops = {
251862306a36Sopenharmony_ci	.ndo_open		= enic_open,
251962306a36Sopenharmony_ci	.ndo_stop		= enic_stop,
252062306a36Sopenharmony_ci	.ndo_start_xmit		= enic_hard_start_xmit,
252162306a36Sopenharmony_ci	.ndo_get_stats64	= enic_get_stats,
252262306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
252362306a36Sopenharmony_ci	.ndo_set_mac_address	= enic_set_mac_address,
252462306a36Sopenharmony_ci	.ndo_set_rx_mode	= enic_set_rx_mode,
252562306a36Sopenharmony_ci	.ndo_change_mtu		= enic_change_mtu,
252662306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid	= enic_vlan_rx_add_vid,
252762306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid	= enic_vlan_rx_kill_vid,
252862306a36Sopenharmony_ci	.ndo_tx_timeout		= enic_tx_timeout,
252962306a36Sopenharmony_ci	.ndo_set_vf_port	= enic_set_vf_port,
253062306a36Sopenharmony_ci	.ndo_get_vf_port	= enic_get_vf_port,
253162306a36Sopenharmony_ci	.ndo_set_vf_mac		= enic_set_vf_mac,
253262306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
253362306a36Sopenharmony_ci	.ndo_poll_controller	= enic_poll_controller,
253462306a36Sopenharmony_ci#endif
253562306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
253662306a36Sopenharmony_ci	.ndo_rx_flow_steer	= enic_rx_flow_steer,
253762306a36Sopenharmony_ci#endif
253862306a36Sopenharmony_ci	.ndo_features_check	= enic_features_check,
253962306a36Sopenharmony_ci};
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_cistatic void enic_dev_deinit(struct enic *enic)
254262306a36Sopenharmony_ci{
254362306a36Sopenharmony_ci	unsigned int i;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	for (i = 0; i < enic->rq_count; i++)
254662306a36Sopenharmony_ci		__netif_napi_del(&enic->napi[i]);
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX)
254962306a36Sopenharmony_ci		for (i = 0; i < enic->wq_count; i++)
255062306a36Sopenharmony_ci			__netif_napi_del(&enic->napi[enic_cq_wq(enic, i)]);
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ci	/* observe RCU grace period after __netif_napi_del() calls */
255362306a36Sopenharmony_ci	synchronize_net();
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	enic_free_vnic_resources(enic);
255662306a36Sopenharmony_ci	enic_clear_intr_mode(enic);
255762306a36Sopenharmony_ci	enic_free_affinity_hint(enic);
255862306a36Sopenharmony_ci}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_cistatic void enic_kdump_kernel_config(struct enic *enic)
256162306a36Sopenharmony_ci{
256262306a36Sopenharmony_ci	if (is_kdump_kernel()) {
256362306a36Sopenharmony_ci		dev_info(enic_get_dev(enic), "Running from within kdump kernel. Using minimal resources\n");
256462306a36Sopenharmony_ci		enic->rq_count = 1;
256562306a36Sopenharmony_ci		enic->wq_count = 1;
256662306a36Sopenharmony_ci		enic->config.rq_desc_count = ENIC_MIN_RQ_DESCS;
256762306a36Sopenharmony_ci		enic->config.wq_desc_count = ENIC_MIN_WQ_DESCS;
256862306a36Sopenharmony_ci		enic->config.mtu = min_t(u16, 1500, enic->config.mtu);
256962306a36Sopenharmony_ci	}
257062306a36Sopenharmony_ci}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_cistatic int enic_dev_init(struct enic *enic)
257362306a36Sopenharmony_ci{
257462306a36Sopenharmony_ci	struct device *dev = enic_get_dev(enic);
257562306a36Sopenharmony_ci	struct net_device *netdev = enic->netdev;
257662306a36Sopenharmony_ci	unsigned int i;
257762306a36Sopenharmony_ci	int err;
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci	/* Get interrupt coalesce timer info */
258062306a36Sopenharmony_ci	err = enic_dev_intr_coal_timer_info(enic);
258162306a36Sopenharmony_ci	if (err) {
258262306a36Sopenharmony_ci		dev_warn(dev, "Using default conversion factor for "
258362306a36Sopenharmony_ci			"interrupt coalesce timer\n");
258462306a36Sopenharmony_ci		vnic_dev_intr_coal_timer_info_default(enic->vdev);
258562306a36Sopenharmony_ci	}
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	/* Get vNIC configuration
258862306a36Sopenharmony_ci	 */
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	err = enic_get_vnic_config(enic);
259162306a36Sopenharmony_ci	if (err) {
259262306a36Sopenharmony_ci		dev_err(dev, "Get vNIC configuration failed, aborting\n");
259362306a36Sopenharmony_ci		return err;
259462306a36Sopenharmony_ci	}
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	/* Get available resource counts
259762306a36Sopenharmony_ci	 */
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci	enic_get_res_counts(enic);
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	/* modify resource count if we are in kdump_kernel
260262306a36Sopenharmony_ci	 */
260362306a36Sopenharmony_ci	enic_kdump_kernel_config(enic);
260462306a36Sopenharmony_ci
260562306a36Sopenharmony_ci	/* Set interrupt mode based on resource counts and system
260662306a36Sopenharmony_ci	 * capabilities
260762306a36Sopenharmony_ci	 */
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	err = enic_set_intr_mode(enic);
261062306a36Sopenharmony_ci	if (err) {
261162306a36Sopenharmony_ci		dev_err(dev, "Failed to set intr mode based on resource "
261262306a36Sopenharmony_ci			"counts and system capabilities, aborting\n");
261362306a36Sopenharmony_ci		return err;
261462306a36Sopenharmony_ci	}
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	/* Allocate and configure vNIC resources
261762306a36Sopenharmony_ci	 */
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci	err = enic_alloc_vnic_resources(enic);
262062306a36Sopenharmony_ci	if (err) {
262162306a36Sopenharmony_ci		dev_err(dev, "Failed to alloc vNIC resources, aborting\n");
262262306a36Sopenharmony_ci		goto err_out_free_vnic_resources;
262362306a36Sopenharmony_ci	}
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	enic_init_vnic_resources(enic);
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	err = enic_set_rss_nic_cfg(enic);
262862306a36Sopenharmony_ci	if (err) {
262962306a36Sopenharmony_ci		dev_err(dev, "Failed to config nic, aborting\n");
263062306a36Sopenharmony_ci		goto err_out_free_vnic_resources;
263162306a36Sopenharmony_ci	}
263262306a36Sopenharmony_ci
263362306a36Sopenharmony_ci	switch (vnic_dev_get_intr_mode(enic->vdev)) {
263462306a36Sopenharmony_ci	default:
263562306a36Sopenharmony_ci		netif_napi_add(netdev, &enic->napi[0], enic_poll);
263662306a36Sopenharmony_ci		break;
263762306a36Sopenharmony_ci	case VNIC_DEV_INTR_MODE_MSIX:
263862306a36Sopenharmony_ci		for (i = 0; i < enic->rq_count; i++) {
263962306a36Sopenharmony_ci			netif_napi_add(netdev, &enic->napi[i],
264062306a36Sopenharmony_ci				       enic_poll_msix_rq);
264162306a36Sopenharmony_ci		}
264262306a36Sopenharmony_ci		for (i = 0; i < enic->wq_count; i++)
264362306a36Sopenharmony_ci			netif_napi_add(netdev,
264462306a36Sopenharmony_ci				       &enic->napi[enic_cq_wq(enic, i)],
264562306a36Sopenharmony_ci				       enic_poll_msix_wq);
264662306a36Sopenharmony_ci		break;
264762306a36Sopenharmony_ci	}
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	return 0;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_cierr_out_free_vnic_resources:
265262306a36Sopenharmony_ci	enic_free_affinity_hint(enic);
265362306a36Sopenharmony_ci	enic_clear_intr_mode(enic);
265462306a36Sopenharmony_ci	enic_free_vnic_resources(enic);
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	return err;
265762306a36Sopenharmony_ci}
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_cistatic void enic_iounmap(struct enic *enic)
266062306a36Sopenharmony_ci{
266162306a36Sopenharmony_ci	unsigned int i;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(enic->bar); i++)
266462306a36Sopenharmony_ci		if (enic->bar[i].vaddr)
266562306a36Sopenharmony_ci			iounmap(enic->bar[i].vaddr);
266662306a36Sopenharmony_ci}
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_cistatic int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
266962306a36Sopenharmony_ci{
267062306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
267162306a36Sopenharmony_ci	struct net_device *netdev;
267262306a36Sopenharmony_ci	struct enic *enic;
267362306a36Sopenharmony_ci	int using_dac = 0;
267462306a36Sopenharmony_ci	unsigned int i;
267562306a36Sopenharmony_ci	int err;
267662306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
267762306a36Sopenharmony_ci	int pos = 0;
267862306a36Sopenharmony_ci#endif
267962306a36Sopenharmony_ci	int num_pps = 1;
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	/* Allocate net device structure and initialize.  Private
268262306a36Sopenharmony_ci	 * instance data is initialized to zero.
268362306a36Sopenharmony_ci	 */
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci	netdev = alloc_etherdev_mqs(sizeof(struct enic),
268662306a36Sopenharmony_ci				    ENIC_RQ_MAX, ENIC_WQ_MAX);
268762306a36Sopenharmony_ci	if (!netdev)
268862306a36Sopenharmony_ci		return -ENOMEM;
268962306a36Sopenharmony_ci
269062306a36Sopenharmony_ci	pci_set_drvdata(pdev, netdev);
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	SET_NETDEV_DEV(netdev, &pdev->dev);
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	enic = netdev_priv(netdev);
269562306a36Sopenharmony_ci	enic->netdev = netdev;
269662306a36Sopenharmony_ci	enic->pdev = pdev;
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	/* Setup PCI resources
269962306a36Sopenharmony_ci	 */
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	err = pci_enable_device_mem(pdev);
270262306a36Sopenharmony_ci	if (err) {
270362306a36Sopenharmony_ci		dev_err(dev, "Cannot enable PCI device, aborting\n");
270462306a36Sopenharmony_ci		goto err_out_free_netdev;
270562306a36Sopenharmony_ci	}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	err = pci_request_regions(pdev, DRV_NAME);
270862306a36Sopenharmony_ci	if (err) {
270962306a36Sopenharmony_ci		dev_err(dev, "Cannot request PCI regions, aborting\n");
271062306a36Sopenharmony_ci		goto err_out_disable_device;
271162306a36Sopenharmony_ci	}
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci	pci_set_master(pdev);
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	/* Query PCI controller on system for DMA addressing
271662306a36Sopenharmony_ci	 * limitation for the device.  Try 47-bit first, and
271762306a36Sopenharmony_ci	 * fail to 32-bit.
271862306a36Sopenharmony_ci	 */
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(47));
272162306a36Sopenharmony_ci	if (err) {
272262306a36Sopenharmony_ci		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
272362306a36Sopenharmony_ci		if (err) {
272462306a36Sopenharmony_ci			dev_err(dev, "No usable DMA configuration, aborting\n");
272562306a36Sopenharmony_ci			goto err_out_release_regions;
272662306a36Sopenharmony_ci		}
272762306a36Sopenharmony_ci	} else {
272862306a36Sopenharmony_ci		using_dac = 1;
272962306a36Sopenharmony_ci	}
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci	/* Map vNIC resources from BAR0-5
273262306a36Sopenharmony_ci	 */
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(enic->bar); i++) {
273562306a36Sopenharmony_ci		if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM))
273662306a36Sopenharmony_ci			continue;
273762306a36Sopenharmony_ci		enic->bar[i].len = pci_resource_len(pdev, i);
273862306a36Sopenharmony_ci		enic->bar[i].vaddr = pci_iomap(pdev, i, enic->bar[i].len);
273962306a36Sopenharmony_ci		if (!enic->bar[i].vaddr) {
274062306a36Sopenharmony_ci			dev_err(dev, "Cannot memory-map BAR %d, aborting\n", i);
274162306a36Sopenharmony_ci			err = -ENODEV;
274262306a36Sopenharmony_ci			goto err_out_iounmap;
274362306a36Sopenharmony_ci		}
274462306a36Sopenharmony_ci		enic->bar[i].bus_addr = pci_resource_start(pdev, i);
274562306a36Sopenharmony_ci	}
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	/* Register vNIC device
274862306a36Sopenharmony_ci	 */
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_ci	enic->vdev = vnic_dev_register(NULL, enic, pdev, enic->bar,
275162306a36Sopenharmony_ci		ARRAY_SIZE(enic->bar));
275262306a36Sopenharmony_ci	if (!enic->vdev) {
275362306a36Sopenharmony_ci		dev_err(dev, "vNIC registration failed, aborting\n");
275462306a36Sopenharmony_ci		err = -ENODEV;
275562306a36Sopenharmony_ci		goto err_out_iounmap;
275662306a36Sopenharmony_ci	}
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	err = vnic_devcmd_init(enic->vdev);
275962306a36Sopenharmony_ci
276062306a36Sopenharmony_ci	if (err)
276162306a36Sopenharmony_ci		goto err_out_vnic_unregister;
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
276462306a36Sopenharmony_ci	/* Get number of subvnics */
276562306a36Sopenharmony_ci	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
276662306a36Sopenharmony_ci	if (pos) {
276762306a36Sopenharmony_ci		pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF,
276862306a36Sopenharmony_ci			&enic->num_vfs);
276962306a36Sopenharmony_ci		if (enic->num_vfs) {
277062306a36Sopenharmony_ci			err = pci_enable_sriov(pdev, enic->num_vfs);
277162306a36Sopenharmony_ci			if (err) {
277262306a36Sopenharmony_ci				dev_err(dev, "SRIOV enable failed, aborting."
277362306a36Sopenharmony_ci					" pci_enable_sriov() returned %d\n",
277462306a36Sopenharmony_ci					err);
277562306a36Sopenharmony_ci				goto err_out_vnic_unregister;
277662306a36Sopenharmony_ci			}
277762306a36Sopenharmony_ci			enic->priv_flags |= ENIC_SRIOV_ENABLED;
277862306a36Sopenharmony_ci			num_pps = enic->num_vfs;
277962306a36Sopenharmony_ci		}
278062306a36Sopenharmony_ci	}
278162306a36Sopenharmony_ci#endif
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	/* Allocate structure for port profiles */
278462306a36Sopenharmony_ci	enic->pp = kcalloc(num_pps, sizeof(*enic->pp), GFP_KERNEL);
278562306a36Sopenharmony_ci	if (!enic->pp) {
278662306a36Sopenharmony_ci		err = -ENOMEM;
278762306a36Sopenharmony_ci		goto err_out_disable_sriov_pp;
278862306a36Sopenharmony_ci	}
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	/* Issue device open to get device in known state
279162306a36Sopenharmony_ci	 */
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci	err = enic_dev_open(enic);
279462306a36Sopenharmony_ci	if (err) {
279562306a36Sopenharmony_ci		dev_err(dev, "vNIC dev open failed, aborting\n");
279662306a36Sopenharmony_ci		goto err_out_disable_sriov;
279762306a36Sopenharmony_ci	}
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci	/* Setup devcmd lock
280062306a36Sopenharmony_ci	 */
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	spin_lock_init(&enic->devcmd_lock);
280362306a36Sopenharmony_ci	spin_lock_init(&enic->enic_api_lock);
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	/*
280662306a36Sopenharmony_ci	 * Set ingress vlan rewrite mode before vnic initialization
280762306a36Sopenharmony_ci	 */
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	err = enic_dev_set_ig_vlan_rewrite_mode(enic);
281062306a36Sopenharmony_ci	if (err) {
281162306a36Sopenharmony_ci		dev_err(dev,
281262306a36Sopenharmony_ci			"Failed to set ingress vlan rewrite mode, aborting.\n");
281362306a36Sopenharmony_ci		goto err_out_dev_close;
281462306a36Sopenharmony_ci	}
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci	/* Issue device init to initialize the vnic-to-switch link.
281762306a36Sopenharmony_ci	 * We'll start with carrier off and wait for link UP
281862306a36Sopenharmony_ci	 * notification later to turn on carrier.  We don't need
281962306a36Sopenharmony_ci	 * to wait here for the vnic-to-switch link initialization
282062306a36Sopenharmony_ci	 * to complete; link UP notification is the indication that
282162306a36Sopenharmony_ci	 * the process is complete.
282262306a36Sopenharmony_ci	 */
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	netif_carrier_off(netdev);
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci	/* Do not call dev_init for a dynamic vnic.
282762306a36Sopenharmony_ci	 * For a dynamic vnic, init_prov_info will be
282862306a36Sopenharmony_ci	 * called later by an upper layer.
282962306a36Sopenharmony_ci	 */
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	if (!enic_is_dynamic(enic)) {
283262306a36Sopenharmony_ci		err = vnic_dev_init(enic->vdev, 0);
283362306a36Sopenharmony_ci		if (err) {
283462306a36Sopenharmony_ci			dev_err(dev, "vNIC dev init failed, aborting\n");
283562306a36Sopenharmony_ci			goto err_out_dev_close;
283662306a36Sopenharmony_ci		}
283762306a36Sopenharmony_ci	}
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	err = enic_dev_init(enic);
284062306a36Sopenharmony_ci	if (err) {
284162306a36Sopenharmony_ci		dev_err(dev, "Device initialization failed, aborting\n");
284262306a36Sopenharmony_ci		goto err_out_dev_close;
284362306a36Sopenharmony_ci	}
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	netif_set_real_num_tx_queues(netdev, enic->wq_count);
284662306a36Sopenharmony_ci	netif_set_real_num_rx_queues(netdev, enic->rq_count);
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	/* Setup notification timer, HW reset task, and wq locks
284962306a36Sopenharmony_ci	 */
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci	timer_setup(&enic->notify_timer, enic_notify_timer, 0);
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	enic_rfs_flw_tbl_init(enic);
285462306a36Sopenharmony_ci	enic_set_rx_coal_setting(enic);
285562306a36Sopenharmony_ci	INIT_WORK(&enic->reset, enic_reset);
285662306a36Sopenharmony_ci	INIT_WORK(&enic->tx_hang_reset, enic_tx_hang_reset);
285762306a36Sopenharmony_ci	INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work);
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci	for (i = 0; i < enic->wq_count; i++)
286062306a36Sopenharmony_ci		spin_lock_init(&enic->wq_lock[i]);
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	/* Register net device
286362306a36Sopenharmony_ci	 */
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	enic->port_mtu = enic->config.mtu;
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci	err = enic_set_mac_addr(netdev, enic->mac_addr);
286862306a36Sopenharmony_ci	if (err) {
286962306a36Sopenharmony_ci		dev_err(dev, "Invalid MAC address, aborting\n");
287062306a36Sopenharmony_ci		goto err_out_dev_deinit;
287162306a36Sopenharmony_ci	}
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
287462306a36Sopenharmony_ci	/* rx coalesce time already got initialized. This gets used
287562306a36Sopenharmony_ci	 * if adaptive coal is turned off
287662306a36Sopenharmony_ci	 */
287762306a36Sopenharmony_ci	enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci	if (enic_is_dynamic(enic) || enic_is_sriov_vf(enic))
288062306a36Sopenharmony_ci		netdev->netdev_ops = &enic_netdev_dynamic_ops;
288162306a36Sopenharmony_ci	else
288262306a36Sopenharmony_ci		netdev->netdev_ops = &enic_netdev_ops;
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	netdev->watchdog_timeo = 2 * HZ;
288562306a36Sopenharmony_ci	enic_set_ethtool_ops(netdev);
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
288862306a36Sopenharmony_ci	if (ENIC_SETTING(enic, LOOP)) {
288962306a36Sopenharmony_ci		netdev->features &= ~NETIF_F_HW_VLAN_CTAG_TX;
289062306a36Sopenharmony_ci		enic->loop_enable = 1;
289162306a36Sopenharmony_ci		enic->loop_tag = enic->config.loop_tag;
289262306a36Sopenharmony_ci		dev_info(dev, "loopback tag=0x%04x\n", enic->loop_tag);
289362306a36Sopenharmony_ci	}
289462306a36Sopenharmony_ci	if (ENIC_SETTING(enic, TXCSUM))
289562306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM;
289662306a36Sopenharmony_ci	if (ENIC_SETTING(enic, TSO))
289762306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_TSO |
289862306a36Sopenharmony_ci			NETIF_F_TSO6 | NETIF_F_TSO_ECN;
289962306a36Sopenharmony_ci	if (ENIC_SETTING(enic, RSS))
290062306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_RXHASH;
290162306a36Sopenharmony_ci	if (ENIC_SETTING(enic, RXCSUM))
290262306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_RXCSUM;
290362306a36Sopenharmony_ci	if (ENIC_SETTING(enic, VXLAN)) {
290462306a36Sopenharmony_ci		u64 patch_level;
290562306a36Sopenharmony_ci		u64 a1 = 0;
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci		netdev->hw_enc_features |= NETIF_F_RXCSUM		|
290862306a36Sopenharmony_ci					   NETIF_F_TSO			|
290962306a36Sopenharmony_ci					   NETIF_F_TSO6			|
291062306a36Sopenharmony_ci					   NETIF_F_TSO_ECN		|
291162306a36Sopenharmony_ci					   NETIF_F_GSO_UDP_TUNNEL	|
291262306a36Sopenharmony_ci					   NETIF_F_HW_CSUM		|
291362306a36Sopenharmony_ci					   NETIF_F_GSO_UDP_TUNNEL_CSUM;
291462306a36Sopenharmony_ci		netdev->hw_features |= netdev->hw_enc_features;
291562306a36Sopenharmony_ci		/* get bit mask from hw about supported offload bit level
291662306a36Sopenharmony_ci		 * BIT(0) = fw supports patch_level 0
291762306a36Sopenharmony_ci		 *	    fcoe bit = encap
291862306a36Sopenharmony_ci		 *	    fcoe_fc_crc_ok = outer csum ok
291962306a36Sopenharmony_ci		 * BIT(1) = always set by fw
292062306a36Sopenharmony_ci		 * BIT(2) = fw supports patch_level 2
292162306a36Sopenharmony_ci		 *	    BIT(0) in rss_hash = encap
292262306a36Sopenharmony_ci		 *	    BIT(1,2) in rss_hash = outer_ip_csum_ok/
292362306a36Sopenharmony_ci		 *				   outer_tcp_csum_ok
292462306a36Sopenharmony_ci		 * used in enic_rq_indicate_buf
292562306a36Sopenharmony_ci		 */
292662306a36Sopenharmony_ci		err = vnic_dev_get_supported_feature_ver(enic->vdev,
292762306a36Sopenharmony_ci							 VIC_FEATURE_VXLAN,
292862306a36Sopenharmony_ci							 &patch_level, &a1);
292962306a36Sopenharmony_ci		if (err)
293062306a36Sopenharmony_ci			patch_level = 0;
293162306a36Sopenharmony_ci		enic->vxlan.flags = (u8)a1;
293262306a36Sopenharmony_ci		/* mask bits that are supported by driver
293362306a36Sopenharmony_ci		 */
293462306a36Sopenharmony_ci		patch_level &= BIT_ULL(0) | BIT_ULL(2);
293562306a36Sopenharmony_ci		patch_level = fls(patch_level);
293662306a36Sopenharmony_ci		patch_level = patch_level ? patch_level - 1 : 0;
293762306a36Sopenharmony_ci		enic->vxlan.patch_level = patch_level;
293862306a36Sopenharmony_ci
293962306a36Sopenharmony_ci		if (vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ) == 1 ||
294062306a36Sopenharmony_ci		    enic->vxlan.flags & ENIC_VXLAN_MULTI_WQ) {
294162306a36Sopenharmony_ci			netdev->udp_tunnel_nic_info = &enic_udp_tunnels_v4;
294262306a36Sopenharmony_ci			if (enic->vxlan.flags & ENIC_VXLAN_OUTER_IPV6)
294362306a36Sopenharmony_ci				netdev->udp_tunnel_nic_info = &enic_udp_tunnels;
294462306a36Sopenharmony_ci		}
294562306a36Sopenharmony_ci	}
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_ci	netdev->features |= netdev->hw_features;
294862306a36Sopenharmony_ci	netdev->vlan_features |= netdev->features;
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
295162306a36Sopenharmony_ci	netdev->hw_features |= NETIF_F_NTUPLE;
295262306a36Sopenharmony_ci#endif
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci	if (using_dac)
295562306a36Sopenharmony_ci		netdev->features |= NETIF_F_HIGHDMA;
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	netdev->priv_flags |= IFF_UNICAST_FLT;
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	/* MTU range: 68 - 9000 */
296062306a36Sopenharmony_ci	netdev->min_mtu = ENIC_MIN_MTU;
296162306a36Sopenharmony_ci	netdev->max_mtu = ENIC_MAX_MTU;
296262306a36Sopenharmony_ci	netdev->mtu	= enic->port_mtu;
296362306a36Sopenharmony_ci
296462306a36Sopenharmony_ci	err = register_netdev(netdev);
296562306a36Sopenharmony_ci	if (err) {
296662306a36Sopenharmony_ci		dev_err(dev, "Cannot register net device, aborting\n");
296762306a36Sopenharmony_ci		goto err_out_dev_deinit;
296862306a36Sopenharmony_ci	}
296962306a36Sopenharmony_ci	enic->rx_copybreak = RX_COPYBREAK_DEFAULT;
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	return 0;
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_cierr_out_dev_deinit:
297462306a36Sopenharmony_ci	enic_dev_deinit(enic);
297562306a36Sopenharmony_cierr_out_dev_close:
297662306a36Sopenharmony_ci	vnic_dev_close(enic->vdev);
297762306a36Sopenharmony_cierr_out_disable_sriov:
297862306a36Sopenharmony_ci	kfree(enic->pp);
297962306a36Sopenharmony_cierr_out_disable_sriov_pp:
298062306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
298162306a36Sopenharmony_ci	if (enic_sriov_enabled(enic)) {
298262306a36Sopenharmony_ci		pci_disable_sriov(pdev);
298362306a36Sopenharmony_ci		enic->priv_flags &= ~ENIC_SRIOV_ENABLED;
298462306a36Sopenharmony_ci	}
298562306a36Sopenharmony_ci#endif
298662306a36Sopenharmony_cierr_out_vnic_unregister:
298762306a36Sopenharmony_ci	vnic_dev_unregister(enic->vdev);
298862306a36Sopenharmony_cierr_out_iounmap:
298962306a36Sopenharmony_ci	enic_iounmap(enic);
299062306a36Sopenharmony_cierr_out_release_regions:
299162306a36Sopenharmony_ci	pci_release_regions(pdev);
299262306a36Sopenharmony_cierr_out_disable_device:
299362306a36Sopenharmony_ci	pci_disable_device(pdev);
299462306a36Sopenharmony_cierr_out_free_netdev:
299562306a36Sopenharmony_ci	free_netdev(netdev);
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	return err;
299862306a36Sopenharmony_ci}
299962306a36Sopenharmony_ci
300062306a36Sopenharmony_cistatic void enic_remove(struct pci_dev *pdev)
300162306a36Sopenharmony_ci{
300262306a36Sopenharmony_ci	struct net_device *netdev = pci_get_drvdata(pdev);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	if (netdev) {
300562306a36Sopenharmony_ci		struct enic *enic = netdev_priv(netdev);
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci		cancel_work_sync(&enic->reset);
300862306a36Sopenharmony_ci		cancel_work_sync(&enic->change_mtu_work);
300962306a36Sopenharmony_ci		unregister_netdev(netdev);
301062306a36Sopenharmony_ci		enic_dev_deinit(enic);
301162306a36Sopenharmony_ci		vnic_dev_close(enic->vdev);
301262306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
301362306a36Sopenharmony_ci		if (enic_sriov_enabled(enic)) {
301462306a36Sopenharmony_ci			pci_disable_sriov(pdev);
301562306a36Sopenharmony_ci			enic->priv_flags &= ~ENIC_SRIOV_ENABLED;
301662306a36Sopenharmony_ci		}
301762306a36Sopenharmony_ci#endif
301862306a36Sopenharmony_ci		kfree(enic->pp);
301962306a36Sopenharmony_ci		vnic_dev_unregister(enic->vdev);
302062306a36Sopenharmony_ci		enic_iounmap(enic);
302162306a36Sopenharmony_ci		pci_release_regions(pdev);
302262306a36Sopenharmony_ci		pci_disable_device(pdev);
302362306a36Sopenharmony_ci		free_netdev(netdev);
302462306a36Sopenharmony_ci	}
302562306a36Sopenharmony_ci}
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_cistatic struct pci_driver enic_driver = {
302862306a36Sopenharmony_ci	.name = DRV_NAME,
302962306a36Sopenharmony_ci	.id_table = enic_id_table,
303062306a36Sopenharmony_ci	.probe = enic_probe,
303162306a36Sopenharmony_ci	.remove = enic_remove,
303262306a36Sopenharmony_ci};
303362306a36Sopenharmony_ci
303462306a36Sopenharmony_cimodule_pci_driver(enic_driver);
3035