xref: /dpdk/drivers/net/enic/enic_main.c (revision bbab3d97c37e55f05064efd7cefd965f6ff0661b)
172f3de30SBruce Richardson /*
272f3de30SBruce Richardson  * Copyright 2008-2014 Cisco Systems, Inc.  All rights reserved.
372f3de30SBruce Richardson  * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
472f3de30SBruce Richardson  *
572f3de30SBruce Richardson  * Copyright (c) 2014, Cisco Systems, Inc.
672f3de30SBruce Richardson  * All rights reserved.
772f3de30SBruce Richardson  *
872f3de30SBruce Richardson  * Redistribution and use in source and binary forms, with or without
972f3de30SBruce Richardson  * modification, are permitted provided that the following conditions
1072f3de30SBruce Richardson  * are met:
1172f3de30SBruce Richardson  *
1272f3de30SBruce Richardson  * 1. Redistributions of source code must retain the above copyright
1372f3de30SBruce Richardson  * notice, this list of conditions and the following disclaimer.
1472f3de30SBruce Richardson  *
1572f3de30SBruce Richardson  * 2. Redistributions in binary form must reproduce the above copyright
1672f3de30SBruce Richardson  * notice, this list of conditions and the following disclaimer in
1772f3de30SBruce Richardson  * the documentation and/or other materials provided with the
1872f3de30SBruce Richardson  * distribution.
1972f3de30SBruce Richardson  *
2072f3de30SBruce Richardson  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2172f3de30SBruce Richardson  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2272f3de30SBruce Richardson  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2372f3de30SBruce Richardson  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2472f3de30SBruce Richardson  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2572f3de30SBruce Richardson  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2672f3de30SBruce Richardson  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2772f3de30SBruce Richardson  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2872f3de30SBruce Richardson  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2972f3de30SBruce Richardson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3072f3de30SBruce Richardson  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3172f3de30SBruce Richardson  * POSSIBILITY OF SUCH DAMAGE.
3272f3de30SBruce Richardson  *
3372f3de30SBruce Richardson  */
3472f3de30SBruce Richardson 
3572f3de30SBruce Richardson #include <stdio.h>
3672f3de30SBruce Richardson 
3772f3de30SBruce Richardson #include <sys/stat.h>
3872f3de30SBruce Richardson #include <sys/mman.h>
3972f3de30SBruce Richardson #include <fcntl.h>
4072f3de30SBruce Richardson #include <libgen.h>
4172f3de30SBruce Richardson 
4272f3de30SBruce Richardson #include <rte_pci.h>
4372f3de30SBruce Richardson #include <rte_memzone.h>
4472f3de30SBruce Richardson #include <rte_malloc.h>
4572f3de30SBruce Richardson #include <rte_mbuf.h>
4672f3de30SBruce Richardson #include <rte_string_fns.h>
4772f3de30SBruce Richardson #include <rte_ethdev.h>
4872f3de30SBruce Richardson 
4972f3de30SBruce Richardson #include "enic_compat.h"
5072f3de30SBruce Richardson #include "enic.h"
5172f3de30SBruce Richardson #include "wq_enet_desc.h"
5272f3de30SBruce Richardson #include "rq_enet_desc.h"
5372f3de30SBruce Richardson #include "cq_enet_desc.h"
5472f3de30SBruce Richardson #include "vnic_enet.h"
5572f3de30SBruce Richardson #include "vnic_dev.h"
5672f3de30SBruce Richardson #include "vnic_wq.h"
5772f3de30SBruce Richardson #include "vnic_rq.h"
5872f3de30SBruce Richardson #include "vnic_cq.h"
5972f3de30SBruce Richardson #include "vnic_intr.h"
6072f3de30SBruce Richardson #include "vnic_nic.h"
6172f3de30SBruce Richardson 
6272f3de30SBruce Richardson static inline int enic_is_sriov_vf(struct enic *enic)
6372f3de30SBruce Richardson {
6472f3de30SBruce Richardson 	return enic->pdev->id.device_id == PCI_DEVICE_ID_CISCO_VIC_ENET_VF;
6572f3de30SBruce Richardson }
6672f3de30SBruce Richardson 
6772f3de30SBruce Richardson static int is_zero_addr(uint8_t *addr)
6872f3de30SBruce Richardson {
6972f3de30SBruce Richardson 	return !(addr[0] |  addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
7072f3de30SBruce Richardson }
7172f3de30SBruce Richardson 
7272f3de30SBruce Richardson static int is_mcast_addr(uint8_t *addr)
7372f3de30SBruce Richardson {
7472f3de30SBruce Richardson 	return addr[0] & 1;
7572f3de30SBruce Richardson }
7672f3de30SBruce Richardson 
7772f3de30SBruce Richardson static int is_eth_addr_valid(uint8_t *addr)
7872f3de30SBruce Richardson {
7972f3de30SBruce Richardson 	return !is_mcast_addr(addr) && !is_zero_addr(addr);
8072f3de30SBruce Richardson }
8172f3de30SBruce Richardson 
82947d860cSJohn Daley static void
83a44a1724SNelson Escobar enic_rxmbuf_queue_release(__rte_unused struct enic *enic, struct vnic_rq *rq)
8472f3de30SBruce Richardson {
85947d860cSJohn Daley 	uint16_t i;
8672f3de30SBruce Richardson 
87947d860cSJohn Daley 	if (!rq || !rq->mbuf_ring) {
88947d860cSJohn Daley 		dev_debug(enic, "Pointer to rq or mbuf_ring is NULL");
89947d860cSJohn Daley 		return;
9072f3de30SBruce Richardson 	}
9172f3de30SBruce Richardson 
92a44a1724SNelson Escobar 	for (i = 0; i < rq->ring.desc_count; i++) {
93947d860cSJohn Daley 		if (rq->mbuf_ring[i]) {
94947d860cSJohn Daley 			rte_pktmbuf_free_seg(rq->mbuf_ring[i]);
95947d860cSJohn Daley 			rq->mbuf_ring[i] = NULL;
96947d860cSJohn Daley 		}
97947d860cSJohn Daley 	}
98947d860cSJohn Daley }
99947d860cSJohn Daley 
10072f3de30SBruce Richardson void enic_set_hdr_split_size(struct enic *enic, u16 split_hdr_size)
10172f3de30SBruce Richardson {
10272f3de30SBruce Richardson 	vnic_set_hdr_split_size(enic->vdev, split_hdr_size);
10372f3de30SBruce Richardson }
10472f3de30SBruce Richardson 
1059455b237SJohn Daley static void enic_free_wq_buf(struct vnic_wq_buf *buf)
10672f3de30SBruce Richardson {
107a3b1e955SJohn Daley 	struct rte_mbuf *mbuf = (struct rte_mbuf *)buf->mb;
10872f3de30SBruce Richardson 
109da24f6f6SJohn Daley 	rte_pktmbuf_free_seg(mbuf);
110a3b1e955SJohn Daley 	buf->mb = NULL;
11172f3de30SBruce Richardson }
11272f3de30SBruce Richardson 
11372f3de30SBruce Richardson static void enic_log_q_error(struct enic *enic)
11472f3de30SBruce Richardson {
11572f3de30SBruce Richardson 	unsigned int i;
11672f3de30SBruce Richardson 	u32 error_status;
11772f3de30SBruce Richardson 
11872f3de30SBruce Richardson 	for (i = 0; i < enic->wq_count; i++) {
11972f3de30SBruce Richardson 		error_status = vnic_wq_error_status(&enic->wq[i]);
12072f3de30SBruce Richardson 		if (error_status)
12172f3de30SBruce Richardson 			dev_err(enic, "WQ[%d] error_status %d\n", i,
12272f3de30SBruce Richardson 				error_status);
12372f3de30SBruce Richardson 	}
12472f3de30SBruce Richardson 
125856d7ba7SNelson Escobar 	for (i = 0; i < enic_vnic_rq_count(enic); i++) {
126e3725e7fSNelson Escobar 		if (!enic->rq[i].in_use)
127e3725e7fSNelson Escobar 			continue;
12872f3de30SBruce Richardson 		error_status = vnic_rq_error_status(&enic->rq[i]);
12972f3de30SBruce Richardson 		if (error_status)
13072f3de30SBruce Richardson 			dev_err(enic, "RQ[%d] error_status %d\n", i,
13172f3de30SBruce Richardson 				error_status);
13272f3de30SBruce Richardson 	}
13372f3de30SBruce Richardson }
13472f3de30SBruce Richardson 
13565b5434dSJohn Daley static void enic_clear_soft_stats(struct enic *enic)
13665b5434dSJohn Daley {
13765b5434dSJohn Daley 	struct enic_soft_stats *soft_stats = &enic->soft_stats;
13865b5434dSJohn Daley 	rte_atomic64_clear(&soft_stats->rx_nombuf);
139c44d9f01SJohn Daley 	rte_atomic64_clear(&soft_stats->rx_packet_errors);
14065b5434dSJohn Daley }
14165b5434dSJohn Daley 
14265b5434dSJohn Daley static void enic_init_soft_stats(struct enic *enic)
14365b5434dSJohn Daley {
14465b5434dSJohn Daley 	struct enic_soft_stats *soft_stats = &enic->soft_stats;
14565b5434dSJohn Daley 	rte_atomic64_init(&soft_stats->rx_nombuf);
146c44d9f01SJohn Daley 	rte_atomic64_init(&soft_stats->rx_packet_errors);
14765b5434dSJohn Daley 	enic_clear_soft_stats(enic);
14865b5434dSJohn Daley }
14965b5434dSJohn Daley 
15072f3de30SBruce Richardson void enic_dev_stats_clear(struct enic *enic)
15172f3de30SBruce Richardson {
15272f3de30SBruce Richardson 	if (vnic_dev_stats_clear(enic->vdev))
15372f3de30SBruce Richardson 		dev_err(enic, "Error in clearing stats\n");
15465b5434dSJohn Daley 	enic_clear_soft_stats(enic);
15572f3de30SBruce Richardson }
15672f3de30SBruce Richardson 
15772f3de30SBruce Richardson void enic_dev_stats_get(struct enic *enic, struct rte_eth_stats *r_stats)
15872f3de30SBruce Richardson {
15972f3de30SBruce Richardson 	struct vnic_stats *stats;
160c44d9f01SJohn Daley 	struct enic_soft_stats *soft_stats = &enic->soft_stats;
161c44d9f01SJohn Daley 	int64_t rx_truncated;
162c44d9f01SJohn Daley 	uint64_t rx_packet_errors;
16372f3de30SBruce Richardson 
16472f3de30SBruce Richardson 	if (vnic_dev_stats_dump(enic->vdev, &stats)) {
16572f3de30SBruce Richardson 		dev_err(enic, "Error in getting stats\n");
16672f3de30SBruce Richardson 		return;
16772f3de30SBruce Richardson 	}
16872f3de30SBruce Richardson 
169c44d9f01SJohn Daley 	/* The number of truncated packets can only be calculated by
170c44d9f01SJohn Daley 	 * subtracting a hardware counter from error packets received by
171c44d9f01SJohn Daley 	 * the driver. Note: this causes transient inaccuracies in the
172c44d9f01SJohn Daley 	 * ipackets count. Also, the length of truncated packets are
173c44d9f01SJohn Daley 	 * counted in ibytes even though truncated packets are dropped
174c44d9f01SJohn Daley 	 * which can make ibytes be slightly higher than it should be.
175c44d9f01SJohn Daley 	 */
176c44d9f01SJohn Daley 	rx_packet_errors = rte_atomic64_read(&soft_stats->rx_packet_errors);
177c92efcaeSNelson Escobar 	rx_truncated = rx_packet_errors - stats->rx.rx_errors;
178c44d9f01SJohn Daley 
179c44d9f01SJohn Daley 	r_stats->ipackets = stats->rx.rx_frames_ok - rx_truncated;
18072f3de30SBruce Richardson 	r_stats->opackets = stats->tx.tx_frames_ok;
18172f3de30SBruce Richardson 
18272f3de30SBruce Richardson 	r_stats->ibytes = stats->rx.rx_bytes_ok;
18372f3de30SBruce Richardson 	r_stats->obytes = stats->tx.tx_bytes_ok;
18472f3de30SBruce Richardson 
18565b5434dSJohn Daley 	r_stats->ierrors = stats->rx.rx_errors + stats->rx.rx_drop;
18672f3de30SBruce Richardson 	r_stats->oerrors = stats->tx.tx_errors;
18772f3de30SBruce Richardson 
188c44d9f01SJohn Daley 	r_stats->imissed = stats->rx.rx_no_bufs + rx_truncated;
1897182d3e7SJohn Daley 
19065b5434dSJohn Daley 	r_stats->rx_nombuf = rte_atomic64_read(&soft_stats->rx_nombuf);
19172f3de30SBruce Richardson }
19272f3de30SBruce Richardson 
193*bbab3d97SJohn Daley void enic_del_mac_address(struct enic *enic, int mac_index)
19472f3de30SBruce Richardson {
195*bbab3d97SJohn Daley 	struct rte_eth_dev *eth_dev = enic->rte_dev;
196*bbab3d97SJohn Daley 	uint8_t *mac_addr = eth_dev->data->mac_addrs[mac_index].addr_bytes;
197*bbab3d97SJohn Daley 
198*bbab3d97SJohn Daley 	if (vnic_dev_del_addr(enic->vdev, mac_addr))
19972f3de30SBruce Richardson 		dev_err(enic, "del mac addr failed\n");
20072f3de30SBruce Richardson }
20172f3de30SBruce Richardson 
20272f3de30SBruce Richardson void enic_set_mac_address(struct enic *enic, uint8_t *mac_addr)
20372f3de30SBruce Richardson {
20472f3de30SBruce Richardson 	int err;
20572f3de30SBruce Richardson 
20672f3de30SBruce Richardson 	if (!is_eth_addr_valid(mac_addr)) {
20772f3de30SBruce Richardson 		dev_err(enic, "invalid mac address\n");
20872f3de30SBruce Richardson 		return;
20972f3de30SBruce Richardson 	}
21072f3de30SBruce Richardson 
21172f3de30SBruce Richardson 	err = vnic_dev_add_addr(enic->vdev, mac_addr);
21272f3de30SBruce Richardson 	if (err) {
21372f3de30SBruce Richardson 		dev_err(enic, "add mac addr failed\n");
21472f3de30SBruce Richardson 		return;
21572f3de30SBruce Richardson 	}
21672f3de30SBruce Richardson }
21772f3de30SBruce Richardson 
21872f3de30SBruce Richardson static void
219947d860cSJohn Daley enic_free_rq_buf(struct rte_mbuf **mbuf)
22072f3de30SBruce Richardson {
221947d860cSJohn Daley 	if (*mbuf == NULL)
22272f3de30SBruce Richardson 		return;
22372f3de30SBruce Richardson 
224947d860cSJohn Daley 	rte_pktmbuf_free(*mbuf);
225947d860cSJohn Daley 	mbuf = NULL;
22672f3de30SBruce Richardson }
22772f3de30SBruce Richardson 
22872f3de30SBruce Richardson void enic_init_vnic_resources(struct enic *enic)
22972f3de30SBruce Richardson {
23072f3de30SBruce Richardson 	unsigned int error_interrupt_enable = 1;
23172f3de30SBruce Richardson 	unsigned int error_interrupt_offset = 0;
23272f3de30SBruce Richardson 	unsigned int index = 0;
233fc2c8c06SJohn Daley 	unsigned int cq_idx;
234856d7ba7SNelson Escobar 	struct vnic_rq *data_rq;
23572f3de30SBruce Richardson 
23672f3de30SBruce Richardson 	for (index = 0; index < enic->rq_count; index++) {
237aa07bf8fSJohn Daley 		cq_idx = enic_cq_rq(enic, enic_rte_rq_idx_to_sop_idx(index));
23816dba071SNelson Escobar 
239aa07bf8fSJohn Daley 		vnic_rq_init(&enic->rq[enic_rte_rq_idx_to_sop_idx(index)],
24016dba071SNelson Escobar 			cq_idx,
241856d7ba7SNelson Escobar 			error_interrupt_enable,
242856d7ba7SNelson Escobar 			error_interrupt_offset);
243856d7ba7SNelson Escobar 
244aa07bf8fSJohn Daley 		data_rq = &enic->rq[enic_rte_rq_idx_to_data_idx(index)];
245856d7ba7SNelson Escobar 		if (data_rq->in_use)
246856d7ba7SNelson Escobar 			vnic_rq_init(data_rq,
24716dba071SNelson Escobar 				     cq_idx,
24872f3de30SBruce Richardson 				     error_interrupt_enable,
24972f3de30SBruce Richardson 				     error_interrupt_offset);
25072f3de30SBruce Richardson 
251fc2c8c06SJohn Daley 		vnic_cq_init(&enic->cq[cq_idx],
25272f3de30SBruce Richardson 			0 /* flow_control_enable */,
25372f3de30SBruce Richardson 			1 /* color_enable */,
25472f3de30SBruce Richardson 			0 /* cq_head */,
25572f3de30SBruce Richardson 			0 /* cq_tail */,
25672f3de30SBruce Richardson 			1 /* cq_tail_color */,
25772f3de30SBruce Richardson 			0 /* interrupt_enable */,
25872f3de30SBruce Richardson 			1 /* cq_entry_enable */,
25972f3de30SBruce Richardson 			0 /* cq_message_enable */,
26072f3de30SBruce Richardson 			0 /* interrupt offset */,
26172f3de30SBruce Richardson 			0 /* cq_message_addr */);
26272f3de30SBruce Richardson 	}
26372f3de30SBruce Richardson 
264fc2c8c06SJohn Daley 	for (index = 0; index < enic->wq_count; index++) {
265fc2c8c06SJohn Daley 		vnic_wq_init(&enic->wq[index],
266fc2c8c06SJohn Daley 			enic_cq_wq(enic, index),
267fc2c8c06SJohn Daley 			error_interrupt_enable,
268fc2c8c06SJohn Daley 			error_interrupt_offset);
269fc2c8c06SJohn Daley 
270fc2c8c06SJohn Daley 		cq_idx = enic_cq_wq(enic, index);
271fc2c8c06SJohn Daley 		vnic_cq_init(&enic->cq[cq_idx],
272fc2c8c06SJohn Daley 			0 /* flow_control_enable */,
273fc2c8c06SJohn Daley 			1 /* color_enable */,
274fc2c8c06SJohn Daley 			0 /* cq_head */,
275fc2c8c06SJohn Daley 			0 /* cq_tail */,
276fc2c8c06SJohn Daley 			1 /* cq_tail_color */,
277fc2c8c06SJohn Daley 			0 /* interrupt_enable */,
278fc2c8c06SJohn Daley 			0 /* cq_entry_enable */,
279fc2c8c06SJohn Daley 			1 /* cq_message_enable */,
280fc2c8c06SJohn Daley 			0 /* interrupt offset */,
281fc2c8c06SJohn Daley 			(u64)enic->wq[index].cqmsg_rz->phys_addr);
282fc2c8c06SJohn Daley 	}
283fc2c8c06SJohn Daley 
28472f3de30SBruce Richardson 	vnic_intr_init(&enic->intr,
28572f3de30SBruce Richardson 		enic->config.intr_timer_usec,
28672f3de30SBruce Richardson 		enic->config.intr_timer_type,
28772f3de30SBruce Richardson 		/*mask_on_assertion*/1);
28872f3de30SBruce Richardson }
28972f3de30SBruce Richardson 
29072f3de30SBruce Richardson 
291947d860cSJohn Daley static int
292947d860cSJohn Daley enic_alloc_rx_queue_mbufs(struct enic *enic, struct vnic_rq *rq)
29372f3de30SBruce Richardson {
294947d860cSJohn Daley 	struct rte_mbuf *mb;
295947d860cSJohn Daley 	struct rq_enet_desc *rqd = rq->ring.descs;
296947d860cSJohn Daley 	unsigned i;
29772f3de30SBruce Richardson 	dma_addr_t dma_addr;
29872f3de30SBruce Richardson 
299856d7ba7SNelson Escobar 	if (!rq->in_use)
300856d7ba7SNelson Escobar 		return 0;
301856d7ba7SNelson Escobar 
302bba57df3SNelson Escobar 	dev_debug(enic, "queue %u, allocating %u rx queue mbufs\n", rq->index,
303947d860cSJohn Daley 		  rq->ring.desc_count);
304947d860cSJohn Daley 
305947d860cSJohn Daley 	for (i = 0; i < rq->ring.desc_count; i++, rqd++) {
306fbfd9955SOlivier Matz 		mb = rte_mbuf_raw_alloc(rq->mp);
307947d860cSJohn Daley 		if (mb == NULL) {
308bba57df3SNelson Escobar 			dev_err(enic, "RX mbuf alloc failed queue_id=%u\n",
309947d860cSJohn Daley 			(unsigned)rq->index);
310947d860cSJohn Daley 			return -ENOMEM;
31172f3de30SBruce Richardson 		}
31272f3de30SBruce Richardson 
3131ccc51b0SJohn Daley 		mb->data_off = RTE_PKTMBUF_HEADROOM;
3144a3259d6SJohn Daley 		dma_addr = (dma_addr_t)(mb->buf_physaddr
3154a3259d6SJohn Daley 			   + RTE_PKTMBUF_HEADROOM);
316856d7ba7SNelson Escobar 		rq_enet_desc_enc(rqd, dma_addr,
317856d7ba7SNelson Escobar 				(rq->is_sop ? RQ_ENET_TYPE_ONLY_SOP
318856d7ba7SNelson Escobar 				: RQ_ENET_TYPE_NOT_SOP),
3194a3259d6SJohn Daley 				mb->buf_len - RTE_PKTMBUF_HEADROOM);
320947d860cSJohn Daley 		rq->mbuf_ring[i] = mb;
32172f3de30SBruce Richardson 	}
32272f3de30SBruce Richardson 
323947d860cSJohn Daley 	/* make sure all prior writes are complete before doing the PIO write */
324947d860cSJohn Daley 	rte_rmb();
32572f3de30SBruce Richardson 
326856d7ba7SNelson Escobar 	/* Post all but the last buffer to VIC. */
327856d7ba7SNelson Escobar 	rq->posted_index = rq->ring.desc_count - 1;
328856d7ba7SNelson Escobar 
329947d860cSJohn Daley 	rq->rx_nb_hold = 0;
33072f3de30SBruce Richardson 
331947d860cSJohn Daley 	dev_debug(enic, "port=%u, qidx=%u, Write %u posted idx, %u sw held\n",
332947d860cSJohn Daley 		enic->port_id, rq->index, rq->posted_index, rq->rx_nb_hold);
333947d860cSJohn Daley 	iowrite32(rq->posted_index, &rq->ctrl->posted_index);
33404f97689SJohn Daley 	iowrite32(0, &rq->ctrl->fetch_index);
335947d860cSJohn Daley 	rte_rmb();
33672f3de30SBruce Richardson 
33772f3de30SBruce Richardson 	return 0;
33872f3de30SBruce Richardson 
33972f3de30SBruce Richardson }
34072f3de30SBruce Richardson 
34172f3de30SBruce Richardson static void *
342da5f560bSNelson Escobar enic_alloc_consistent(void *priv, size_t size,
34372f3de30SBruce Richardson 	dma_addr_t *dma_handle, u8 *name)
34472f3de30SBruce Richardson {
34572f3de30SBruce Richardson 	void *vaddr;
34672f3de30SBruce Richardson 	const struct rte_memzone *rz;
34772f3de30SBruce Richardson 	*dma_handle = 0;
348da5f560bSNelson Escobar 	struct enic *enic = (struct enic *)priv;
349da5f560bSNelson Escobar 	struct enic_memzone_entry *mze;
35072f3de30SBruce Richardson 
35172f3de30SBruce Richardson 	rz = rte_memzone_reserve_aligned((const char *)name,
3527a0b8b7cSDavid Marchand 					 size, SOCKET_ID_ANY, 0, ENIC_ALIGN);
35372f3de30SBruce Richardson 	if (!rz) {
354bba57df3SNelson Escobar 		pr_err("%s : Failed to allocate memory requested for %s\n",
35572f3de30SBruce Richardson 			__func__, name);
35672f3de30SBruce Richardson 		return NULL;
35772f3de30SBruce Richardson 	}
35872f3de30SBruce Richardson 
35972f3de30SBruce Richardson 	vaddr = rz->addr;
36072f3de30SBruce Richardson 	*dma_handle = (dma_addr_t)rz->phys_addr;
36172f3de30SBruce Richardson 
362da5f560bSNelson Escobar 	mze = rte_malloc("enic memzone entry",
363da5f560bSNelson Escobar 			 sizeof(struct enic_memzone_entry), 0);
364da5f560bSNelson Escobar 
365da5f560bSNelson Escobar 	if (!mze) {
366da5f560bSNelson Escobar 		pr_err("%s : Failed to allocate memory for memzone list\n",
367da5f560bSNelson Escobar 		       __func__);
368da5f560bSNelson Escobar 		rte_memzone_free(rz);
369da5f560bSNelson Escobar 	}
370da5f560bSNelson Escobar 
371da5f560bSNelson Escobar 	mze->rz = rz;
372da5f560bSNelson Escobar 
373da5f560bSNelson Escobar 	rte_spinlock_lock(&enic->memzone_list_lock);
374da5f560bSNelson Escobar 	LIST_INSERT_HEAD(&enic->memzone_list, mze, entries);
375da5f560bSNelson Escobar 	rte_spinlock_unlock(&enic->memzone_list_lock);
376da5f560bSNelson Escobar 
37772f3de30SBruce Richardson 	return vaddr;
37872f3de30SBruce Richardson }
37972f3de30SBruce Richardson 
38072f3de30SBruce Richardson static void
381da5f560bSNelson Escobar enic_free_consistent(void *priv,
38272f3de30SBruce Richardson 		     __rte_unused size_t size,
383da5f560bSNelson Escobar 		     void *vaddr,
384da5f560bSNelson Escobar 		     dma_addr_t dma_handle)
38572f3de30SBruce Richardson {
386da5f560bSNelson Escobar 	struct enic_memzone_entry *mze;
387da5f560bSNelson Escobar 	struct enic *enic = (struct enic *)priv;
388da5f560bSNelson Escobar 
389da5f560bSNelson Escobar 	rte_spinlock_lock(&enic->memzone_list_lock);
390da5f560bSNelson Escobar 	LIST_FOREACH(mze, &enic->memzone_list, entries) {
391da5f560bSNelson Escobar 		if (mze->rz->addr == vaddr &&
392da5f560bSNelson Escobar 		    mze->rz->phys_addr == dma_handle)
393da5f560bSNelson Escobar 			break;
394da5f560bSNelson Escobar 	}
395da5f560bSNelson Escobar 	if (mze == NULL) {
396da5f560bSNelson Escobar 		rte_spinlock_unlock(&enic->memzone_list_lock);
397da5f560bSNelson Escobar 		dev_warning(enic,
398da5f560bSNelson Escobar 			    "Tried to free memory, but couldn't find it in the memzone list\n");
399da5f560bSNelson Escobar 		return;
400da5f560bSNelson Escobar 	}
401da5f560bSNelson Escobar 	LIST_REMOVE(mze, entries);
402da5f560bSNelson Escobar 	rte_spinlock_unlock(&enic->memzone_list_lock);
403da5f560bSNelson Escobar 	rte_memzone_free(mze->rz);
404da5f560bSNelson Escobar 	rte_free(mze);
40572f3de30SBruce Richardson }
40672f3de30SBruce Richardson 
407cf8d9826SNelson Escobar int enic_link_update(struct enic *enic)
408cf8d9826SNelson Escobar {
409cf8d9826SNelson Escobar 	struct rte_eth_dev *eth_dev = enic->rte_dev;
410cf8d9826SNelson Escobar 	int ret;
411cf8d9826SNelson Escobar 	int link_status = 0;
412cf8d9826SNelson Escobar 
413cf8d9826SNelson Escobar 	link_status = enic_get_link_status(enic);
414cf8d9826SNelson Escobar 	ret = (link_status == enic->link_status);
415cf8d9826SNelson Escobar 	enic->link_status = link_status;
416cf8d9826SNelson Escobar 	eth_dev->data->dev_link.link_status = link_status;
417cf8d9826SNelson Escobar 	eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX;
418cf8d9826SNelson Escobar 	eth_dev->data->dev_link.link_speed = vnic_dev_port_speed(enic->vdev);
419cf8d9826SNelson Escobar 	return ret;
420cf8d9826SNelson Escobar }
421cf8d9826SNelson Escobar 
42272f3de30SBruce Richardson static void
42372f3de30SBruce Richardson enic_intr_handler(__rte_unused struct rte_intr_handle *handle,
42472f3de30SBruce Richardson 	void *arg)
42572f3de30SBruce Richardson {
42653fa8cc0SNelson Escobar 	struct rte_eth_dev *dev = (struct rte_eth_dev *)arg;
42753fa8cc0SNelson Escobar 	struct enic *enic = pmd_priv(dev);
42872f3de30SBruce Richardson 
42972f3de30SBruce Richardson 	vnic_intr_return_all_credits(&enic->intr);
43072f3de30SBruce Richardson 
43153fa8cc0SNelson Escobar 	enic_link_update(enic);
432c1ceaf3aSBernard Iremonger 	_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
43372f3de30SBruce Richardson 	enic_log_q_error(enic);
43472f3de30SBruce Richardson }
43572f3de30SBruce Richardson 
43672f3de30SBruce Richardson int enic_enable(struct enic *enic)
43772f3de30SBruce Richardson {
43872f3de30SBruce Richardson 	unsigned int index;
439947d860cSJohn Daley 	int err;
44072f3de30SBruce Richardson 	struct rte_eth_dev *eth_dev = enic->rte_dev;
44172f3de30SBruce Richardson 
44272f3de30SBruce Richardson 	eth_dev->data->dev_link.link_speed = vnic_dev_port_speed(enic->vdev);
44372f3de30SBruce Richardson 	eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX;
44472f3de30SBruce Richardson 
44553fa8cc0SNelson Escobar 	/* vnic notification of link status has already been turned on in
44653fa8cc0SNelson Escobar 	 * enic_dev_init() which is called during probe time.  Here we are
44753fa8cc0SNelson Escobar 	 * just turning on interrupt vector 0 if needed.
44853fa8cc0SNelson Escobar 	 */
44953fa8cc0SNelson Escobar 	if (eth_dev->data->dev_conf.intr_conf.lsc)
45053fa8cc0SNelson Escobar 		vnic_dev_notify_set(enic->vdev, 0);
45153fa8cc0SNelson Escobar 
45272f3de30SBruce Richardson 	if (enic_clsf_init(enic))
45372f3de30SBruce Richardson 		dev_warning(enic, "Init of hash table for clsf failed."\
45472f3de30SBruce Richardson 			"Flow director feature will not work\n");
45572f3de30SBruce Richardson 
45672f3de30SBruce Richardson 	for (index = 0; index < enic->rq_count; index++) {
457856d7ba7SNelson Escobar 		err = enic_alloc_rx_queue_mbufs(enic,
458aa07bf8fSJohn Daley 			&enic->rq[enic_rte_rq_idx_to_sop_idx(index)]);
459947d860cSJohn Daley 		if (err) {
460856d7ba7SNelson Escobar 			dev_err(enic, "Failed to alloc sop RX queue mbufs\n");
461856d7ba7SNelson Escobar 			return err;
462856d7ba7SNelson Escobar 		}
463856d7ba7SNelson Escobar 		err = enic_alloc_rx_queue_mbufs(enic,
464aa07bf8fSJohn Daley 			&enic->rq[enic_rte_rq_idx_to_data_idx(index)]);
465856d7ba7SNelson Escobar 		if (err) {
466856d7ba7SNelson Escobar 			/* release the allocated mbufs for the sop rq*/
467856d7ba7SNelson Escobar 			enic_rxmbuf_queue_release(enic,
468aa07bf8fSJohn Daley 				&enic->rq[enic_rte_rq_idx_to_sop_idx(index)]);
469856d7ba7SNelson Escobar 
470856d7ba7SNelson Escobar 			dev_err(enic, "Failed to alloc data RX queue mbufs\n");
471947d860cSJohn Daley 			return err;
47272f3de30SBruce Richardson 		}
47372f3de30SBruce Richardson 	}
47472f3de30SBruce Richardson 
47572f3de30SBruce Richardson 	for (index = 0; index < enic->wq_count; index++)
476856d7ba7SNelson Escobar 		enic_start_wq(enic, index);
47772f3de30SBruce Richardson 	for (index = 0; index < enic->rq_count; index++)
478856d7ba7SNelson Escobar 		enic_start_rq(enic, index);
47972f3de30SBruce Richardson 
480e5b60cf1SNelson Escobar 	vnic_dev_add_addr(enic->vdev, enic->mac_addr);
481e5b60cf1SNelson Escobar 
48272f3de30SBruce Richardson 	vnic_dev_enable_wait(enic->vdev);
48372f3de30SBruce Richardson 
48472f3de30SBruce Richardson 	/* Register and enable error interrupt */
48572f3de30SBruce Richardson 	rte_intr_callback_register(&(enic->pdev->intr_handle),
48672f3de30SBruce Richardson 		enic_intr_handler, (void *)enic->rte_dev);
48772f3de30SBruce Richardson 
48872f3de30SBruce Richardson 	rte_intr_enable(&(enic->pdev->intr_handle));
48972f3de30SBruce Richardson 	vnic_intr_unmask(&enic->intr);
49072f3de30SBruce Richardson 
49172f3de30SBruce Richardson 	return 0;
49272f3de30SBruce Richardson }
49372f3de30SBruce Richardson 
49472f3de30SBruce Richardson int enic_alloc_intr_resources(struct enic *enic)
49572f3de30SBruce Richardson {
49672f3de30SBruce Richardson 	int err;
49772f3de30SBruce Richardson 
49872f3de30SBruce Richardson 	dev_info(enic, "vNIC resources used:  "\
49972f3de30SBruce Richardson 		"wq %d rq %d cq %d intr %d\n",
500856d7ba7SNelson Escobar 		enic->wq_count, enic_vnic_rq_count(enic),
50172f3de30SBruce Richardson 		enic->cq_count, enic->intr_count);
50272f3de30SBruce Richardson 
50372f3de30SBruce Richardson 	err = vnic_intr_alloc(enic->vdev, &enic->intr, 0);
50472f3de30SBruce Richardson 	if (err)
50572f3de30SBruce Richardson 		enic_free_vnic_resources(enic);
50672f3de30SBruce Richardson 
50772f3de30SBruce Richardson 	return err;
50872f3de30SBruce Richardson }
50972f3de30SBruce Richardson 
51072f3de30SBruce Richardson void enic_free_rq(void *rxq)
51172f3de30SBruce Richardson {
512856d7ba7SNelson Escobar 	struct vnic_rq *rq_sop, *rq_data;
51383a9d8b7SJohn Daley 	struct enic *enic;
51472f3de30SBruce Richardson 
51583a9d8b7SJohn Daley 	if (rxq == NULL)
51683a9d8b7SJohn Daley 		return;
51783a9d8b7SJohn Daley 
518856d7ba7SNelson Escobar 	rq_sop = (struct vnic_rq *)rxq;
519856d7ba7SNelson Escobar 	enic = vnic_dev_priv(rq_sop->vdev);
520856d7ba7SNelson Escobar 	rq_data = &enic->rq[rq_sop->data_queue_idx];
521856d7ba7SNelson Escobar 
522856d7ba7SNelson Escobar 	enic_rxmbuf_queue_release(enic, rq_sop);
523856d7ba7SNelson Escobar 	if (rq_data->in_use)
524856d7ba7SNelson Escobar 		enic_rxmbuf_queue_release(enic, rq_data);
525856d7ba7SNelson Escobar 
526856d7ba7SNelson Escobar 	rte_free(rq_sop->mbuf_ring);
527856d7ba7SNelson Escobar 	if (rq_data->in_use)
528856d7ba7SNelson Escobar 		rte_free(rq_data->mbuf_ring);
529856d7ba7SNelson Escobar 
530856d7ba7SNelson Escobar 	rq_sop->mbuf_ring = NULL;
531856d7ba7SNelson Escobar 	rq_data->mbuf_ring = NULL;
532856d7ba7SNelson Escobar 
533856d7ba7SNelson Escobar 	vnic_rq_free(rq_sop);
534856d7ba7SNelson Escobar 	if (rq_data->in_use)
535856d7ba7SNelson Escobar 		vnic_rq_free(rq_data);
536856d7ba7SNelson Escobar 
537ceeb00b9SJohn Daley 	vnic_cq_free(&enic->cq[enic_sop_rq_idx_to_cq_idx(rq_sop->index)]);
538c3e09182SJohn Daley 
539c3e09182SJohn Daley 	rq_sop->in_use = 0;
540c3e09182SJohn Daley 	rq_data->in_use = 0;
54172f3de30SBruce Richardson }
54272f3de30SBruce Richardson 
54372f3de30SBruce Richardson void enic_start_wq(struct enic *enic, uint16_t queue_idx)
54472f3de30SBruce Richardson {
545837e68aeSJohn Daley 	struct rte_eth_dev *eth_dev = enic->rte_dev;
54672f3de30SBruce Richardson 	vnic_wq_enable(&enic->wq[queue_idx]);
547837e68aeSJohn Daley 	eth_dev->data->tx_queue_state[queue_idx] = RTE_ETH_QUEUE_STATE_STARTED;
54872f3de30SBruce Richardson }
54972f3de30SBruce Richardson 
55072f3de30SBruce Richardson int enic_stop_wq(struct enic *enic, uint16_t queue_idx)
55172f3de30SBruce Richardson {
552837e68aeSJohn Daley 	struct rte_eth_dev *eth_dev = enic->rte_dev;
553837e68aeSJohn Daley 	int ret;
554837e68aeSJohn Daley 
555837e68aeSJohn Daley 	ret = vnic_wq_disable(&enic->wq[queue_idx]);
556837e68aeSJohn Daley 	if (ret)
557837e68aeSJohn Daley 		return ret;
558837e68aeSJohn Daley 
559837e68aeSJohn Daley 	eth_dev->data->tx_queue_state[queue_idx] = RTE_ETH_QUEUE_STATE_STOPPED;
560837e68aeSJohn Daley 	return 0;
56172f3de30SBruce Richardson }
56272f3de30SBruce Richardson 
56372f3de30SBruce Richardson void enic_start_rq(struct enic *enic, uint16_t queue_idx)
56472f3de30SBruce Richardson {
565aa07bf8fSJohn Daley 	struct vnic_rq *rq_sop;
566aa07bf8fSJohn Daley 	struct vnic_rq *rq_data;
567aa07bf8fSJohn Daley 	rq_sop = &enic->rq[enic_rte_rq_idx_to_sop_idx(queue_idx)];
568aa07bf8fSJohn Daley 	rq_data = &enic->rq[rq_sop->data_queue_idx];
569837e68aeSJohn Daley 	struct rte_eth_dev *eth_dev = enic->rte_dev;
570856d7ba7SNelson Escobar 
571856d7ba7SNelson Escobar 	if (rq_data->in_use)
572856d7ba7SNelson Escobar 		vnic_rq_enable(rq_data);
573856d7ba7SNelson Escobar 	rte_mb();
574856d7ba7SNelson Escobar 	vnic_rq_enable(rq_sop);
575837e68aeSJohn Daley 	eth_dev->data->rx_queue_state[queue_idx] = RTE_ETH_QUEUE_STATE_STARTED;
57672f3de30SBruce Richardson }
57772f3de30SBruce Richardson 
57872f3de30SBruce Richardson int enic_stop_rq(struct enic *enic, uint16_t queue_idx)
57972f3de30SBruce Richardson {
580856d7ba7SNelson Escobar 	int ret1 = 0, ret2 = 0;
581837e68aeSJohn Daley 	struct rte_eth_dev *eth_dev = enic->rte_dev;
582aa07bf8fSJohn Daley 	struct vnic_rq *rq_sop;
583aa07bf8fSJohn Daley 	struct vnic_rq *rq_data;
584aa07bf8fSJohn Daley 	rq_sop = &enic->rq[enic_rte_rq_idx_to_sop_idx(queue_idx)];
585aa07bf8fSJohn Daley 	rq_data = &enic->rq[rq_sop->data_queue_idx];
586856d7ba7SNelson Escobar 
587856d7ba7SNelson Escobar 	ret2 = vnic_rq_disable(rq_sop);
588856d7ba7SNelson Escobar 	rte_mb();
589856d7ba7SNelson Escobar 	if (rq_data->in_use)
590856d7ba7SNelson Escobar 		ret1 = vnic_rq_disable(rq_data);
591856d7ba7SNelson Escobar 
592856d7ba7SNelson Escobar 	if (ret2)
593856d7ba7SNelson Escobar 		return ret2;
594837e68aeSJohn Daley 	else if (ret1)
595856d7ba7SNelson Escobar 		return ret1;
596837e68aeSJohn Daley 
597837e68aeSJohn Daley 	eth_dev->data->rx_queue_state[queue_idx] = RTE_ETH_QUEUE_STATE_STOPPED;
598837e68aeSJohn Daley 	return 0;
59972f3de30SBruce Richardson }
60072f3de30SBruce Richardson 
60172f3de30SBruce Richardson int enic_alloc_rq(struct enic *enic, uint16_t queue_idx,
60272f3de30SBruce Richardson 	unsigned int socket_id, struct rte_mempool *mp,
603ce16fd70SJohn Daley 	uint16_t nb_desc, uint16_t free_thresh)
60472f3de30SBruce Richardson {
605947d860cSJohn Daley 	int rc;
606aa07bf8fSJohn Daley 	uint16_t sop_queue_idx = enic_rte_rq_idx_to_sop_idx(queue_idx);
607aa07bf8fSJohn Daley 	uint16_t data_queue_idx = enic_rte_rq_idx_to_data_idx(queue_idx);
608856d7ba7SNelson Escobar 	struct vnic_rq *rq_sop = &enic->rq[sop_queue_idx];
609856d7ba7SNelson Escobar 	struct vnic_rq *rq_data = &enic->rq[data_queue_idx];
610856d7ba7SNelson Escobar 	unsigned int mbuf_size, mbufs_per_pkt;
611856d7ba7SNelson Escobar 	unsigned int nb_sop_desc, nb_data_desc;
612856d7ba7SNelson Escobar 	uint16_t min_sop, max_sop, min_data, max_data;
613c3e09182SJohn Daley 	uint16_t mtu = enic->rte_dev->data->mtu;
61472f3de30SBruce Richardson 
615856d7ba7SNelson Escobar 	rq_sop->is_sop = 1;
616856d7ba7SNelson Escobar 	rq_sop->data_queue_idx = data_queue_idx;
617856d7ba7SNelson Escobar 	rq_data->is_sop = 0;
618856d7ba7SNelson Escobar 	rq_data->data_queue_idx = 0;
619856d7ba7SNelson Escobar 	rq_sop->socket_id = socket_id;
620856d7ba7SNelson Escobar 	rq_sop->mp = mp;
621856d7ba7SNelson Escobar 	rq_data->socket_id = socket_id;
622856d7ba7SNelson Escobar 	rq_data->mp = mp;
623856d7ba7SNelson Escobar 	rq_sop->in_use = 1;
624ce16fd70SJohn Daley 	rq_sop->rx_free_thresh = free_thresh;
625ce16fd70SJohn Daley 	rq_data->rx_free_thresh = free_thresh;
626ce16fd70SJohn Daley 	dev_debug(enic, "Set queue_id:%u free thresh:%u\n", queue_idx,
627ce16fd70SJohn Daley 		  free_thresh);
62872f3de30SBruce Richardson 
629856d7ba7SNelson Escobar 	mbuf_size = (uint16_t)(rte_pktmbuf_data_room_size(mp) -
630856d7ba7SNelson Escobar 			       RTE_PKTMBUF_HEADROOM);
631856d7ba7SNelson Escobar 
632856d7ba7SNelson Escobar 	if (enic->rte_dev->data->dev_conf.rxmode.enable_scatter) {
633c3e09182SJohn Daley 		dev_info(enic, "Rq %u Scatter rx mode enabled\n", queue_idx);
634856d7ba7SNelson Escobar 		/* ceil((mtu + ETHER_HDR_LEN + 4)/mbuf_size) */
635c3e09182SJohn Daley 		mbufs_per_pkt = ((mtu + ETHER_HDR_LEN + 4) +
636856d7ba7SNelson Escobar 				 (mbuf_size - 1)) / mbuf_size;
637856d7ba7SNelson Escobar 	} else {
638856d7ba7SNelson Escobar 		dev_info(enic, "Scatter rx mode disabled\n");
639856d7ba7SNelson Escobar 		mbufs_per_pkt = 1;
640856d7ba7SNelson Escobar 	}
641856d7ba7SNelson Escobar 
642856d7ba7SNelson Escobar 	if (mbufs_per_pkt > 1) {
643c3e09182SJohn Daley 		dev_info(enic, "Rq %u Scatter rx mode in use\n", queue_idx);
644e8a71c46SNelson Escobar 		rq_sop->data_queue_enable = 1;
645856d7ba7SNelson Escobar 		rq_data->in_use = 1;
646856d7ba7SNelson Escobar 	} else {
647c3e09182SJohn Daley 		dev_info(enic, "Rq %u Scatter rx mode not being used\n",
648c3e09182SJohn Daley 			 queue_idx);
649e8a71c46SNelson Escobar 		rq_sop->data_queue_enable = 0;
650856d7ba7SNelson Escobar 		rq_data->in_use = 0;
651856d7ba7SNelson Escobar 	}
652856d7ba7SNelson Escobar 
653856d7ba7SNelson Escobar 	/* number of descriptors have to be a multiple of 32 */
654856d7ba7SNelson Escobar 	nb_sop_desc = (nb_desc / mbufs_per_pkt) & ~0x1F;
655856d7ba7SNelson Escobar 	nb_data_desc = (nb_desc - nb_sop_desc) & ~0x1F;
656856d7ba7SNelson Escobar 
657856d7ba7SNelson Escobar 	rq_sop->max_mbufs_per_pkt = mbufs_per_pkt;
658856d7ba7SNelson Escobar 	rq_data->max_mbufs_per_pkt = mbufs_per_pkt;
659856d7ba7SNelson Escobar 
660856d7ba7SNelson Escobar 	if (mbufs_per_pkt > 1) {
661856d7ba7SNelson Escobar 		min_sop = 64;
662856d7ba7SNelson Escobar 		max_sop = ((enic->config.rq_desc_count /
663856d7ba7SNelson Escobar 			    (mbufs_per_pkt - 1)) & ~0x1F);
664856d7ba7SNelson Escobar 		min_data = min_sop * (mbufs_per_pkt - 1);
665856d7ba7SNelson Escobar 		max_data = enic->config.rq_desc_count;
666856d7ba7SNelson Escobar 	} else {
667856d7ba7SNelson Escobar 		min_sop = 64;
668856d7ba7SNelson Escobar 		max_sop = enic->config.rq_desc_count;
669856d7ba7SNelson Escobar 		min_data = 0;
670856d7ba7SNelson Escobar 		max_data = 0;
671856d7ba7SNelson Escobar 	}
672856d7ba7SNelson Escobar 
673856d7ba7SNelson Escobar 	if (nb_desc < (min_sop + min_data)) {
67472f3de30SBruce Richardson 		dev_warning(enic,
675856d7ba7SNelson Escobar 			    "Number of rx descs too low, adjusting to minimum\n");
676856d7ba7SNelson Escobar 		nb_sop_desc = min_sop;
677856d7ba7SNelson Escobar 		nb_data_desc = min_data;
678856d7ba7SNelson Escobar 	} else if (nb_desc > (max_sop + max_data)) {
679856d7ba7SNelson Escobar 		dev_warning(enic,
680856d7ba7SNelson Escobar 			    "Number of rx_descs too high, adjusting to maximum\n");
681856d7ba7SNelson Escobar 		nb_sop_desc = max_sop;
682856d7ba7SNelson Escobar 		nb_data_desc = max_data;
68372f3de30SBruce Richardson 	}
684856d7ba7SNelson Escobar 	if (mbufs_per_pkt > 1) {
685856d7ba7SNelson Escobar 		dev_info(enic, "For mtu %d and mbuf size %d valid rx descriptor range is %d to %d\n",
686c3e09182SJohn Daley 			 mtu, mbuf_size, min_sop + min_data,
687856d7ba7SNelson Escobar 			 max_sop + max_data);
68872f3de30SBruce Richardson 	}
689856d7ba7SNelson Escobar 	dev_info(enic, "Using %d rx descriptors (sop %d, data %d)\n",
690856d7ba7SNelson Escobar 		 nb_sop_desc + nb_data_desc, nb_sop_desc, nb_data_desc);
69172f3de30SBruce Richardson 
692856d7ba7SNelson Escobar 	/* Allocate sop queue resources */
693856d7ba7SNelson Escobar 	rc = vnic_rq_alloc(enic->vdev, rq_sop, sop_queue_idx,
694856d7ba7SNelson Escobar 		nb_sop_desc, sizeof(struct rq_enet_desc));
695947d860cSJohn Daley 	if (rc) {
696856d7ba7SNelson Escobar 		dev_err(enic, "error in allocation of sop rq\n");
697947d860cSJohn Daley 		goto err_exit;
69872f3de30SBruce Richardson 	}
699856d7ba7SNelson Escobar 	nb_sop_desc = rq_sop->ring.desc_count;
70072f3de30SBruce Richardson 
701856d7ba7SNelson Escobar 	if (rq_data->in_use) {
702856d7ba7SNelson Escobar 		/* Allocate data queue resources */
703856d7ba7SNelson Escobar 		rc = vnic_rq_alloc(enic->vdev, rq_data, data_queue_idx,
704856d7ba7SNelson Escobar 				   nb_data_desc,
705856d7ba7SNelson Escobar 				   sizeof(struct rq_enet_desc));
706856d7ba7SNelson Escobar 		if (rc) {
707856d7ba7SNelson Escobar 			dev_err(enic, "error in allocation of data rq\n");
708856d7ba7SNelson Escobar 			goto err_free_rq_sop;
709856d7ba7SNelson Escobar 		}
710856d7ba7SNelson Escobar 		nb_data_desc = rq_data->ring.desc_count;
711856d7ba7SNelson Escobar 	}
712947d860cSJohn Daley 	rc = vnic_cq_alloc(enic->vdev, &enic->cq[queue_idx], queue_idx,
713856d7ba7SNelson Escobar 			   socket_id, nb_sop_desc + nb_data_desc,
71472f3de30SBruce Richardson 			   sizeof(struct cq_enet_rq_desc));
715947d860cSJohn Daley 	if (rc) {
71672f3de30SBruce Richardson 		dev_err(enic, "error in allocation of cq for rq\n");
717856d7ba7SNelson Escobar 		goto err_free_rq_data;
71872f3de30SBruce Richardson 	}
71972f3de30SBruce Richardson 
720856d7ba7SNelson Escobar 	/* Allocate the mbuf rings */
721856d7ba7SNelson Escobar 	rq_sop->mbuf_ring = (struct rte_mbuf **)
722856d7ba7SNelson Escobar 		rte_zmalloc_socket("rq->mbuf_ring",
723856d7ba7SNelson Escobar 				   sizeof(struct rte_mbuf *) * nb_sop_desc,
724856d7ba7SNelson Escobar 				   RTE_CACHE_LINE_SIZE, rq_sop->socket_id);
725856d7ba7SNelson Escobar 	if (rq_sop->mbuf_ring == NULL)
726856d7ba7SNelson Escobar 		goto err_free_cq;
727947d860cSJohn Daley 
728856d7ba7SNelson Escobar 	if (rq_data->in_use) {
729856d7ba7SNelson Escobar 		rq_data->mbuf_ring = (struct rte_mbuf **)
730856d7ba7SNelson Escobar 			rte_zmalloc_socket("rq->mbuf_ring",
731856d7ba7SNelson Escobar 				sizeof(struct rte_mbuf *) * nb_data_desc,
732856d7ba7SNelson Escobar 				RTE_CACHE_LINE_SIZE, rq_sop->socket_id);
733856d7ba7SNelson Escobar 		if (rq_data->mbuf_ring == NULL)
734856d7ba7SNelson Escobar 			goto err_free_sop_mbuf;
735856d7ba7SNelson Escobar 	}
736856d7ba7SNelson Escobar 
737c3e09182SJohn Daley 	rq_sop->tot_nb_desc = nb_desc; /* squirl away for MTU update function */
738c3e09182SJohn Daley 
739947d860cSJohn Daley 	return 0;
740947d860cSJohn Daley 
741856d7ba7SNelson Escobar err_free_sop_mbuf:
742856d7ba7SNelson Escobar 	rte_free(rq_sop->mbuf_ring);
743856d7ba7SNelson Escobar err_free_cq:
744947d860cSJohn Daley 	/* cleanup on error */
745947d860cSJohn Daley 	vnic_cq_free(&enic->cq[queue_idx]);
746856d7ba7SNelson Escobar err_free_rq_data:
747856d7ba7SNelson Escobar 	if (rq_data->in_use)
748856d7ba7SNelson Escobar 		vnic_rq_free(rq_data);
749856d7ba7SNelson Escobar err_free_rq_sop:
750856d7ba7SNelson Escobar 	vnic_rq_free(rq_sop);
751947d860cSJohn Daley err_exit:
752947d860cSJohn Daley 	return -ENOMEM;
75372f3de30SBruce Richardson }
75472f3de30SBruce Richardson 
75572f3de30SBruce Richardson void enic_free_wq(void *txq)
75672f3de30SBruce Richardson {
75783a9d8b7SJohn Daley 	struct vnic_wq *wq;
75883a9d8b7SJohn Daley 	struct enic *enic;
75972f3de30SBruce Richardson 
76083a9d8b7SJohn Daley 	if (txq == NULL)
76183a9d8b7SJohn Daley 		return;
76283a9d8b7SJohn Daley 
76383a9d8b7SJohn Daley 	wq = (struct vnic_wq *)txq;
76483a9d8b7SJohn Daley 	enic = vnic_dev_priv(wq->vdev);
765fc2c8c06SJohn Daley 	rte_memzone_free(wq->cqmsg_rz);
76672f3de30SBruce Richardson 	vnic_wq_free(wq);
76772f3de30SBruce Richardson 	vnic_cq_free(&enic->cq[enic->rq_count + wq->index]);
76872f3de30SBruce Richardson }
76972f3de30SBruce Richardson 
77072f3de30SBruce Richardson int enic_alloc_wq(struct enic *enic, uint16_t queue_idx,
77172f3de30SBruce Richardson 	unsigned int socket_id, uint16_t nb_desc)
77272f3de30SBruce Richardson {
77372f3de30SBruce Richardson 	int err;
77472f3de30SBruce Richardson 	struct vnic_wq *wq = &enic->wq[queue_idx];
77572f3de30SBruce Richardson 	unsigned int cq_index = enic_cq_wq(enic, queue_idx);
776fc2c8c06SJohn Daley 	char name[NAME_MAX];
777fc2c8c06SJohn Daley 	static int instance;
77872f3de30SBruce Richardson 
77972f3de30SBruce Richardson 	wq->socket_id = socket_id;
78072f3de30SBruce Richardson 	if (nb_desc) {
78172f3de30SBruce Richardson 		if (nb_desc > enic->config.wq_desc_count) {
78272f3de30SBruce Richardson 			dev_warning(enic,
78372f3de30SBruce Richardson 				"WQ %d - number of tx desc in cmd line (%d)"\
78472f3de30SBruce Richardson 				"is greater than that in the UCSM/CIMC adapter"\
78572f3de30SBruce Richardson 				"policy.  Applying the value in the adapter "\
78672f3de30SBruce Richardson 				"policy (%d)\n",
78772f3de30SBruce Richardson 				queue_idx, nb_desc, enic->config.wq_desc_count);
78872f3de30SBruce Richardson 		} else if (nb_desc != enic->config.wq_desc_count) {
78972f3de30SBruce Richardson 			enic->config.wq_desc_count = nb_desc;
79072f3de30SBruce Richardson 			dev_info(enic,
79172f3de30SBruce Richardson 				"TX Queues - effective number of descs:%d\n",
79272f3de30SBruce Richardson 				nb_desc);
79372f3de30SBruce Richardson 		}
79472f3de30SBruce Richardson 	}
79572f3de30SBruce Richardson 
79672f3de30SBruce Richardson 	/* Allocate queue resources */
79772f3de30SBruce Richardson 	err = vnic_wq_alloc(enic->vdev, &enic->wq[queue_idx], queue_idx,
79872f3de30SBruce Richardson 		enic->config.wq_desc_count,
79972f3de30SBruce Richardson 		sizeof(struct wq_enet_desc));
80072f3de30SBruce Richardson 	if (err) {
80172f3de30SBruce Richardson 		dev_err(enic, "error in allocation of wq\n");
80272f3de30SBruce Richardson 		return err;
80372f3de30SBruce Richardson 	}
80472f3de30SBruce Richardson 
80572f3de30SBruce Richardson 	err = vnic_cq_alloc(enic->vdev, &enic->cq[cq_index], cq_index,
80672f3de30SBruce Richardson 		socket_id, enic->config.wq_desc_count,
80772f3de30SBruce Richardson 		sizeof(struct cq_enet_wq_desc));
80872f3de30SBruce Richardson 	if (err) {
80972f3de30SBruce Richardson 		vnic_wq_free(wq);
81072f3de30SBruce Richardson 		dev_err(enic, "error in allocation of cq for wq\n");
81172f3de30SBruce Richardson 	}
81272f3de30SBruce Richardson 
813fc2c8c06SJohn Daley 	/* setup up CQ message */
814fc2c8c06SJohn Daley 	snprintf((char *)name, sizeof(name),
815fc2c8c06SJohn Daley 		 "vnic_cqmsg-%s-%d-%d", enic->bdf_name, queue_idx,
816fc2c8c06SJohn Daley 		instance++);
817fc2c8c06SJohn Daley 
818fc2c8c06SJohn Daley 	wq->cqmsg_rz = rte_memzone_reserve_aligned((const char *)name,
819fc2c8c06SJohn Daley 						   sizeof(uint32_t),
820fc2c8c06SJohn Daley 						   SOCKET_ID_ANY, 0,
821fc2c8c06SJohn Daley 						   ENIC_ALIGN);
822fc2c8c06SJohn Daley 	if (!wq->cqmsg_rz)
823fc2c8c06SJohn Daley 		return -ENOMEM;
824fc2c8c06SJohn Daley 
82572f3de30SBruce Richardson 	return err;
82672f3de30SBruce Richardson }
82772f3de30SBruce Richardson 
82872f3de30SBruce Richardson int enic_disable(struct enic *enic)
82972f3de30SBruce Richardson {
83072f3de30SBruce Richardson 	unsigned int i;
83172f3de30SBruce Richardson 	int err;
83272f3de30SBruce Richardson 
83372f3de30SBruce Richardson 	vnic_intr_mask(&enic->intr);
83472f3de30SBruce Richardson 	(void)vnic_intr_masked(&enic->intr); /* flush write */
835667b8a3bSNelson Escobar 	rte_intr_disable(&enic->pdev->intr_handle);
836667b8a3bSNelson Escobar 	rte_intr_callback_unregister(&enic->pdev->intr_handle,
837667b8a3bSNelson Escobar 				     enic_intr_handler,
838667b8a3bSNelson Escobar 				     (void *)enic->rte_dev);
83972f3de30SBruce Richardson 
84072f3de30SBruce Richardson 	vnic_dev_disable(enic->vdev);
84172f3de30SBruce Richardson 
84272f3de30SBruce Richardson 	enic_clsf_destroy(enic);
84372f3de30SBruce Richardson 
84472f3de30SBruce Richardson 	if (!enic_is_sriov_vf(enic))
84572f3de30SBruce Richardson 		vnic_dev_del_addr(enic->vdev, enic->mac_addr);
84672f3de30SBruce Richardson 
84772f3de30SBruce Richardson 	for (i = 0; i < enic->wq_count; i++) {
84872f3de30SBruce Richardson 		err = vnic_wq_disable(&enic->wq[i]);
84972f3de30SBruce Richardson 		if (err)
85072f3de30SBruce Richardson 			return err;
85172f3de30SBruce Richardson 	}
852856d7ba7SNelson Escobar 	for (i = 0; i < enic_vnic_rq_count(enic); i++) {
853856d7ba7SNelson Escobar 		if (enic->rq[i].in_use) {
85472f3de30SBruce Richardson 			err = vnic_rq_disable(&enic->rq[i]);
85572f3de30SBruce Richardson 			if (err)
85672f3de30SBruce Richardson 				return err;
85772f3de30SBruce Richardson 		}
858856d7ba7SNelson Escobar 	}
85972f3de30SBruce Richardson 
86053fa8cc0SNelson Escobar 	/* If we were using interrupts, set the interrupt vector to -1
86153fa8cc0SNelson Escobar 	 * to disable interrupts.  We are not disabling link notifcations,
86253fa8cc0SNelson Escobar 	 * though, as we want the polling of link status to continue working.
86353fa8cc0SNelson Escobar 	 */
86453fa8cc0SNelson Escobar 	if (enic->rte_dev->data->dev_conf.intr_conf.lsc)
86553fa8cc0SNelson Escobar 		vnic_dev_notify_set(enic->vdev, -1);
86653fa8cc0SNelson Escobar 
86772f3de30SBruce Richardson 	vnic_dev_set_reset_flag(enic->vdev, 1);
86872f3de30SBruce Richardson 
86972f3de30SBruce Richardson 	for (i = 0; i < enic->wq_count; i++)
87072f3de30SBruce Richardson 		vnic_wq_clean(&enic->wq[i], enic_free_wq_buf);
871947d860cSJohn Daley 
872856d7ba7SNelson Escobar 	for (i = 0; i < enic_vnic_rq_count(enic); i++)
873856d7ba7SNelson Escobar 		if (enic->rq[i].in_use)
87472f3de30SBruce Richardson 			vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
87572f3de30SBruce Richardson 	for (i = 0; i < enic->cq_count; i++)
87672f3de30SBruce Richardson 		vnic_cq_clean(&enic->cq[i]);
87772f3de30SBruce Richardson 	vnic_intr_clean(&enic->intr);
87872f3de30SBruce Richardson 
87972f3de30SBruce Richardson 	return 0;
88072f3de30SBruce Richardson }
88172f3de30SBruce Richardson 
88272f3de30SBruce Richardson static int enic_dev_wait(struct vnic_dev *vdev,
88372f3de30SBruce Richardson 	int (*start)(struct vnic_dev *, int),
88472f3de30SBruce Richardson 	int (*finished)(struct vnic_dev *, int *),
88572f3de30SBruce Richardson 	int arg)
88672f3de30SBruce Richardson {
88772f3de30SBruce Richardson 	int done;
88872f3de30SBruce Richardson 	int err;
88972f3de30SBruce Richardson 	int i;
89072f3de30SBruce Richardson 
89172f3de30SBruce Richardson 	err = start(vdev, arg);
89272f3de30SBruce Richardson 	if (err)
89372f3de30SBruce Richardson 		return err;
89472f3de30SBruce Richardson 
89572f3de30SBruce Richardson 	/* Wait for func to complete...2 seconds max */
89672f3de30SBruce Richardson 	for (i = 0; i < 2000; i++) {
89772f3de30SBruce Richardson 		err = finished(vdev, &done);
89872f3de30SBruce Richardson 		if (err)
89972f3de30SBruce Richardson 			return err;
90072f3de30SBruce Richardson 		if (done)
90172f3de30SBruce Richardson 			return 0;
90272f3de30SBruce Richardson 		usleep(1000);
90372f3de30SBruce Richardson 	}
90472f3de30SBruce Richardson 	return -ETIMEDOUT;
90572f3de30SBruce Richardson }
90672f3de30SBruce Richardson 
90772f3de30SBruce Richardson static int enic_dev_open(struct enic *enic)
90872f3de30SBruce Richardson {
90972f3de30SBruce Richardson 	int err;
91072f3de30SBruce Richardson 
91172f3de30SBruce Richardson 	err = enic_dev_wait(enic->vdev, vnic_dev_open,
91272f3de30SBruce Richardson 		vnic_dev_open_done, 0);
91372f3de30SBruce Richardson 	if (err)
91472f3de30SBruce Richardson 		dev_err(enic_get_dev(enic),
91572f3de30SBruce Richardson 			"vNIC device open failed, err %d\n", err);
91672f3de30SBruce Richardson 
91772f3de30SBruce Richardson 	return err;
91872f3de30SBruce Richardson }
91972f3de30SBruce Richardson 
92072f3de30SBruce Richardson static int enic_set_rsskey(struct enic *enic)
92172f3de30SBruce Richardson {
92272f3de30SBruce Richardson 	dma_addr_t rss_key_buf_pa;
92372f3de30SBruce Richardson 	union vnic_rss_key *rss_key_buf_va = NULL;
92472f3de30SBruce Richardson 	static union vnic_rss_key rss_key = {
92572f3de30SBruce Richardson 		.key = {
92672f3de30SBruce Richardson 			[0] = {.b = {85, 67, 83, 97, 119, 101, 115, 111, 109, 101}},
92772f3de30SBruce Richardson 			[1] = {.b = {80, 65, 76, 79, 117, 110, 105, 113, 117, 101}},
92872f3de30SBruce Richardson 			[2] = {.b = {76, 73, 78, 85, 88, 114, 111, 99, 107, 115}},
92972f3de30SBruce Richardson 			[3] = {.b = {69, 78, 73, 67, 105, 115, 99, 111, 111, 108}},
93072f3de30SBruce Richardson 		}
93172f3de30SBruce Richardson 	};
93272f3de30SBruce Richardson 	int err;
93372f3de30SBruce Richardson 	u8 name[NAME_MAX];
93472f3de30SBruce Richardson 
93572f3de30SBruce Richardson 	snprintf((char *)name, NAME_MAX, "rss_key-%s", enic->bdf_name);
93672f3de30SBruce Richardson 	rss_key_buf_va = enic_alloc_consistent(enic, sizeof(union vnic_rss_key),
93772f3de30SBruce Richardson 		&rss_key_buf_pa, name);
93872f3de30SBruce Richardson 	if (!rss_key_buf_va)
93972f3de30SBruce Richardson 		return -ENOMEM;
94072f3de30SBruce Richardson 
94172f3de30SBruce Richardson 	rte_memcpy(rss_key_buf_va, &rss_key, sizeof(union vnic_rss_key));
94272f3de30SBruce Richardson 
94372f3de30SBruce Richardson 	err = enic_set_rss_key(enic,
94472f3de30SBruce Richardson 		rss_key_buf_pa,
94572f3de30SBruce Richardson 		sizeof(union vnic_rss_key));
94672f3de30SBruce Richardson 
947da5f560bSNelson Escobar 	enic_free_consistent(enic, sizeof(union vnic_rss_key),
94872f3de30SBruce Richardson 		rss_key_buf_va, rss_key_buf_pa);
94972f3de30SBruce Richardson 
95072f3de30SBruce Richardson 	return err;
95172f3de30SBruce Richardson }
95272f3de30SBruce Richardson 
95372f3de30SBruce Richardson static int enic_set_rsscpu(struct enic *enic, u8 rss_hash_bits)
95472f3de30SBruce Richardson {
95572f3de30SBruce Richardson 	dma_addr_t rss_cpu_buf_pa;
95672f3de30SBruce Richardson 	union vnic_rss_cpu *rss_cpu_buf_va = NULL;
95772f3de30SBruce Richardson 	int i;
95872f3de30SBruce Richardson 	int err;
95972f3de30SBruce Richardson 	u8 name[NAME_MAX];
96072f3de30SBruce Richardson 
96172f3de30SBruce Richardson 	snprintf((char *)name, NAME_MAX, "rss_cpu-%s", enic->bdf_name);
96272f3de30SBruce Richardson 	rss_cpu_buf_va = enic_alloc_consistent(enic, sizeof(union vnic_rss_cpu),
96372f3de30SBruce Richardson 		&rss_cpu_buf_pa, name);
96472f3de30SBruce Richardson 	if (!rss_cpu_buf_va)
96572f3de30SBruce Richardson 		return -ENOMEM;
96672f3de30SBruce Richardson 
96772f3de30SBruce Richardson 	for (i = 0; i < (1 << rss_hash_bits); i++)
96816dba071SNelson Escobar 		(*rss_cpu_buf_va).cpu[i / 4].b[i % 4] =
969aa07bf8fSJohn Daley 			enic_rte_rq_idx_to_sop_idx(i % enic->rq_count);
97072f3de30SBruce Richardson 
97172f3de30SBruce Richardson 	err = enic_set_rss_cpu(enic,
97272f3de30SBruce Richardson 		rss_cpu_buf_pa,
97372f3de30SBruce Richardson 		sizeof(union vnic_rss_cpu));
97472f3de30SBruce Richardson 
975da5f560bSNelson Escobar 	enic_free_consistent(enic, sizeof(union vnic_rss_cpu),
97672f3de30SBruce Richardson 		rss_cpu_buf_va, rss_cpu_buf_pa);
97772f3de30SBruce Richardson 
97872f3de30SBruce Richardson 	return err;
97972f3de30SBruce Richardson }
98072f3de30SBruce Richardson 
98172f3de30SBruce Richardson static int enic_set_niccfg(struct enic *enic, u8 rss_default_cpu,
98272f3de30SBruce Richardson 	u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable)
98372f3de30SBruce Richardson {
98472f3de30SBruce Richardson 	const u8 tso_ipid_split_en = 0;
98572f3de30SBruce Richardson 	int err;
98672f3de30SBruce Richardson 
98772f3de30SBruce Richardson 	/* Enable VLAN tag stripping */
98872f3de30SBruce Richardson 
98972f3de30SBruce Richardson 	err = enic_set_nic_cfg(enic,
99072f3de30SBruce Richardson 		rss_default_cpu, rss_hash_type,
99172f3de30SBruce Richardson 		rss_hash_bits, rss_base_cpu,
99272f3de30SBruce Richardson 		rss_enable, tso_ipid_split_en,
99372f3de30SBruce Richardson 		enic->ig_vlan_strip_en);
99472f3de30SBruce Richardson 
99572f3de30SBruce Richardson 	return err;
99672f3de30SBruce Richardson }
99772f3de30SBruce Richardson 
99872f3de30SBruce Richardson int enic_set_rss_nic_cfg(struct enic *enic)
99972f3de30SBruce Richardson {
100072f3de30SBruce Richardson 	const u8 rss_default_cpu = 0;
100172f3de30SBruce Richardson 	const u8 rss_hash_type = NIC_CFG_RSS_HASH_TYPE_IPV4 |
100272f3de30SBruce Richardson 	    NIC_CFG_RSS_HASH_TYPE_TCP_IPV4 |
100372f3de30SBruce Richardson 	    NIC_CFG_RSS_HASH_TYPE_IPV6 |
100472f3de30SBruce Richardson 	    NIC_CFG_RSS_HASH_TYPE_TCP_IPV6;
100572f3de30SBruce Richardson 	const u8 rss_hash_bits = 7;
100672f3de30SBruce Richardson 	const u8 rss_base_cpu = 0;
100772f3de30SBruce Richardson 	u8 rss_enable = ENIC_SETTING(enic, RSS) && (enic->rq_count > 1);
100872f3de30SBruce Richardson 
100972f3de30SBruce Richardson 	if (rss_enable) {
101072f3de30SBruce Richardson 		if (!enic_set_rsskey(enic)) {
101172f3de30SBruce Richardson 			if (enic_set_rsscpu(enic, rss_hash_bits)) {
101272f3de30SBruce Richardson 				rss_enable = 0;
101372f3de30SBruce Richardson 				dev_warning(enic, "RSS disabled, "\
101472f3de30SBruce Richardson 					"Failed to set RSS cpu indirection table.");
101572f3de30SBruce Richardson 			}
101672f3de30SBruce Richardson 		} else {
101772f3de30SBruce Richardson 			rss_enable = 0;
101872f3de30SBruce Richardson 			dev_warning(enic,
101972f3de30SBruce Richardson 				"RSS disabled, Failed to set RSS key.\n");
102072f3de30SBruce Richardson 		}
102172f3de30SBruce Richardson 	}
102272f3de30SBruce Richardson 
102372f3de30SBruce Richardson 	return enic_set_niccfg(enic, rss_default_cpu, rss_hash_type,
102472f3de30SBruce Richardson 		rss_hash_bits, rss_base_cpu, rss_enable);
102572f3de30SBruce Richardson }
102672f3de30SBruce Richardson 
102772f3de30SBruce Richardson int enic_setup_finish(struct enic *enic)
102872f3de30SBruce Richardson {
102972f3de30SBruce Richardson 	int ret;
103072f3de30SBruce Richardson 
103165b5434dSJohn Daley 	enic_init_soft_stats(enic);
103265b5434dSJohn Daley 
103372f3de30SBruce Richardson 	ret = enic_set_rss_nic_cfg(enic);
103472f3de30SBruce Richardson 	if (ret) {
103572f3de30SBruce Richardson 		dev_err(enic, "Failed to config nic, aborting.\n");
103672f3de30SBruce Richardson 		return -1;
103772f3de30SBruce Richardson 	}
103872f3de30SBruce Richardson 
103972f3de30SBruce Richardson 	/* Default conf */
104072f3de30SBruce Richardson 	vnic_dev_packet_filter(enic->vdev,
104172f3de30SBruce Richardson 		1 /* directed  */,
104272f3de30SBruce Richardson 		1 /* multicast */,
104372f3de30SBruce Richardson 		1 /* broadcast */,
104472f3de30SBruce Richardson 		0 /* promisc   */,
104572f3de30SBruce Richardson 		1 /* allmulti  */);
104672f3de30SBruce Richardson 
104772f3de30SBruce Richardson 	enic->promisc = 0;
104872f3de30SBruce Richardson 	enic->allmulti = 1;
104972f3de30SBruce Richardson 
105072f3de30SBruce Richardson 	return 0;
105172f3de30SBruce Richardson }
105272f3de30SBruce Richardson 
105372f3de30SBruce Richardson void enic_add_packet_filter(struct enic *enic)
105472f3de30SBruce Richardson {
105572f3de30SBruce Richardson 	/* Args -> directed, multicast, broadcast, promisc, allmulti */
105672f3de30SBruce Richardson 	vnic_dev_packet_filter(enic->vdev, 1, 1, 1,
105772f3de30SBruce Richardson 		enic->promisc, enic->allmulti);
105872f3de30SBruce Richardson }
105972f3de30SBruce Richardson 
106072f3de30SBruce Richardson int enic_get_link_status(struct enic *enic)
106172f3de30SBruce Richardson {
106272f3de30SBruce Richardson 	return vnic_dev_link_status(enic->vdev);
106372f3de30SBruce Richardson }
106472f3de30SBruce Richardson 
106572f3de30SBruce Richardson static void enic_dev_deinit(struct enic *enic)
106672f3de30SBruce Richardson {
106772f3de30SBruce Richardson 	struct rte_eth_dev *eth_dev = enic->rte_dev;
106872f3de30SBruce Richardson 
1069c98779abSNelson Escobar 	/* stop link status checking */
1070c98779abSNelson Escobar 	vnic_dev_notify_unset(enic->vdev);
1071c98779abSNelson Escobar 
107272f3de30SBruce Richardson 	rte_free(eth_dev->data->mac_addrs);
107372f3de30SBruce Richardson }
107472f3de30SBruce Richardson 
107572f3de30SBruce Richardson 
107672f3de30SBruce Richardson int enic_set_vnic_res(struct enic *enic)
107772f3de30SBruce Richardson {
107872f3de30SBruce Richardson 	struct rte_eth_dev *eth_dev = enic->rte_dev;
1079b6d5fd2eSJohn Daley 	int rc = 0;
108072f3de30SBruce Richardson 
1081856d7ba7SNelson Escobar 	/* With Rx scatter support, two RQs are now used per RQ used by
1082856d7ba7SNelson Escobar 	 * the application.
1083856d7ba7SNelson Escobar 	 */
1084ce93d3c3SNelson Escobar 	if (enic->conf_rq_count < eth_dev->data->nb_rx_queues) {
1085856d7ba7SNelson Escobar 		dev_err(dev, "Not enough Receive queues. Requested:%u which uses %d RQs on VIC, Configured:%u\n",
1086856d7ba7SNelson Escobar 			eth_dev->data->nb_rx_queues,
1087ce93d3c3SNelson Escobar 			eth_dev->data->nb_rx_queues * 2, enic->conf_rq_count);
1088b6d5fd2eSJohn Daley 		rc = -EINVAL;
1089b6d5fd2eSJohn Daley 	}
1090ce93d3c3SNelson Escobar 	if (enic->conf_wq_count < eth_dev->data->nb_tx_queues) {
1091b6d5fd2eSJohn Daley 		dev_err(dev, "Not enough Transmit queues. Requested:%u, Configured:%u\n",
1092ce93d3c3SNelson Escobar 			eth_dev->data->nb_tx_queues, enic->conf_wq_count);
1093b6d5fd2eSJohn Daley 		rc = -EINVAL;
109472f3de30SBruce Richardson 	}
109572f3de30SBruce Richardson 
1096ce93d3c3SNelson Escobar 	if (enic->conf_cq_count < (eth_dev->data->nb_rx_queues +
1097ce93d3c3SNelson Escobar 				   eth_dev->data->nb_tx_queues)) {
1098b6d5fd2eSJohn Daley 		dev_err(dev, "Not enough Completion queues. Required:%u, Configured:%u\n",
1099ce93d3c3SNelson Escobar 			(eth_dev->data->nb_rx_queues +
1100ce93d3c3SNelson Escobar 			 eth_dev->data->nb_tx_queues), enic->conf_cq_count);
1101b6d5fd2eSJohn Daley 		rc = -EINVAL;
1102b6d5fd2eSJohn Daley 	}
1103b6d5fd2eSJohn Daley 
1104b6d5fd2eSJohn Daley 	if (rc == 0) {
110572f3de30SBruce Richardson 		enic->rq_count = eth_dev->data->nb_rx_queues;
110672f3de30SBruce Richardson 		enic->wq_count = eth_dev->data->nb_tx_queues;
1107b6d5fd2eSJohn Daley 		enic->cq_count = enic->rq_count + enic->wq_count;
110872f3de30SBruce Richardson 	}
110972f3de30SBruce Richardson 
1110b6d5fd2eSJohn Daley 	return rc;
111172f3de30SBruce Richardson }
111272f3de30SBruce Richardson 
1113c3e09182SJohn Daley /* Initialize the completion queue for an RQ */
1114c3e09182SJohn Daley static int
1115c3e09182SJohn Daley enic_reinit_rq(struct enic *enic, unsigned int rq_idx)
1116c3e09182SJohn Daley {
1117c3e09182SJohn Daley 	struct vnic_rq *sop_rq, *data_rq;
1118c3e09182SJohn Daley 	unsigned int cq_idx = enic_cq_rq(enic, rq_idx);
1119c3e09182SJohn Daley 	int rc = 0;
1120c3e09182SJohn Daley 
1121aa07bf8fSJohn Daley 	sop_rq = &enic->rq[enic_rte_rq_idx_to_sop_idx(rq_idx)];
1122aa07bf8fSJohn Daley 	data_rq = &enic->rq[enic_rte_rq_idx_to_data_idx(rq_idx)];
1123c3e09182SJohn Daley 
1124c3e09182SJohn Daley 	vnic_cq_clean(&enic->cq[cq_idx]);
1125c3e09182SJohn Daley 	vnic_cq_init(&enic->cq[cq_idx],
1126c3e09182SJohn Daley 		     0 /* flow_control_enable */,
1127c3e09182SJohn Daley 		     1 /* color_enable */,
1128c3e09182SJohn Daley 		     0 /* cq_head */,
1129c3e09182SJohn Daley 		     0 /* cq_tail */,
1130c3e09182SJohn Daley 		     1 /* cq_tail_color */,
1131c3e09182SJohn Daley 		     0 /* interrupt_enable */,
1132c3e09182SJohn Daley 		     1 /* cq_entry_enable */,
1133c3e09182SJohn Daley 		     0 /* cq_message_enable */,
1134c3e09182SJohn Daley 		     0 /* interrupt offset */,
1135c3e09182SJohn Daley 		     0 /* cq_message_addr */);
1136c3e09182SJohn Daley 
1137c3e09182SJohn Daley 
1138aa07bf8fSJohn Daley 	vnic_rq_init_start(sop_rq, enic_cq_rq(enic,
1139aa07bf8fSJohn Daley 			   enic_rte_rq_idx_to_sop_idx(rq_idx)), 0,
1140aa07bf8fSJohn Daley 			   sop_rq->ring.desc_count - 1, 1, 0);
1141c3e09182SJohn Daley 	if (data_rq->in_use) {
1142c3e09182SJohn Daley 		vnic_rq_init_start(data_rq,
1143aa07bf8fSJohn Daley 				   enic_cq_rq(enic,
1144aa07bf8fSJohn Daley 				   enic_rte_rq_idx_to_data_idx(rq_idx)), 0,
1145aa07bf8fSJohn Daley 				   data_rq->ring.desc_count - 1, 1, 0);
1146c3e09182SJohn Daley 	}
1147c3e09182SJohn Daley 
1148c3e09182SJohn Daley 	rc = enic_alloc_rx_queue_mbufs(enic, sop_rq);
1149c3e09182SJohn Daley 	if (rc)
1150c3e09182SJohn Daley 		return rc;
1151c3e09182SJohn Daley 
1152c3e09182SJohn Daley 	if (data_rq->in_use) {
1153c3e09182SJohn Daley 		rc = enic_alloc_rx_queue_mbufs(enic, data_rq);
1154c3e09182SJohn Daley 		if (rc) {
1155c3e09182SJohn Daley 			enic_rxmbuf_queue_release(enic, sop_rq);
1156c3e09182SJohn Daley 			return rc;
1157c3e09182SJohn Daley 		}
1158c3e09182SJohn Daley 	}
1159c3e09182SJohn Daley 
1160c3e09182SJohn Daley 	return 0;
1161c3e09182SJohn Daley }
1162c3e09182SJohn Daley 
1163396a6d71SJohn Daley /* The Cisco NIC can send and receive packets up to a max packet size
1164396a6d71SJohn Daley  * determined by the NIC type and firmware. There is also an MTU
1165396a6d71SJohn Daley  * configured into the NIC via the CIMC/UCSM management interface
1166396a6d71SJohn Daley  * which can be overridden by this function (up to the max packet size).
1167396a6d71SJohn Daley  * Depending on the network setup, doing so may cause packet drops
1168396a6d71SJohn Daley  * and unexpected behavior.
1169396a6d71SJohn Daley  */
1170396a6d71SJohn Daley int enic_set_mtu(struct enic *enic, uint16_t new_mtu)
1171396a6d71SJohn Daley {
1172c3e09182SJohn Daley 	unsigned int rq_idx;
1173c3e09182SJohn Daley 	struct vnic_rq *rq;
1174c3e09182SJohn Daley 	int rc = 0;
1175396a6d71SJohn Daley 	uint16_t old_mtu;	/* previous setting */
1176396a6d71SJohn Daley 	uint16_t config_mtu;	/* Value configured into NIC via CIMC/UCSM */
1177396a6d71SJohn Daley 	struct rte_eth_dev *eth_dev = enic->rte_dev;
1178396a6d71SJohn Daley 
1179396a6d71SJohn Daley 	old_mtu = eth_dev->data->mtu;
1180396a6d71SJohn Daley 	config_mtu = enic->config.mtu;
1181396a6d71SJohn Daley 
1182396a6d71SJohn Daley 	if (new_mtu > enic->max_mtu) {
1183396a6d71SJohn Daley 		dev_err(enic,
1184396a6d71SJohn Daley 			"MTU not updated: requested (%u) greater than max (%u)\n",
1185396a6d71SJohn Daley 			new_mtu, enic->max_mtu);
1186396a6d71SJohn Daley 		return -EINVAL;
1187396a6d71SJohn Daley 	}
1188396a6d71SJohn Daley 	if (new_mtu < ENIC_MIN_MTU) {
1189396a6d71SJohn Daley 		dev_info(enic,
1190396a6d71SJohn Daley 			"MTU not updated: requested (%u) less than min (%u)\n",
1191396a6d71SJohn Daley 			new_mtu, ENIC_MIN_MTU);
1192396a6d71SJohn Daley 		return -EINVAL;
1193396a6d71SJohn Daley 	}
1194396a6d71SJohn Daley 	if (new_mtu > config_mtu)
1195396a6d71SJohn Daley 		dev_warning(enic,
1196396a6d71SJohn Daley 			"MTU (%u) is greater than value configured in NIC (%u)\n",
1197396a6d71SJohn Daley 			new_mtu, config_mtu);
1198396a6d71SJohn Daley 
1199c3e09182SJohn Daley 	/* The easy case is when scatter is disabled. However if the MTU
1200c3e09182SJohn Daley 	 * becomes greater than the mbuf data size, packet drops will ensue.
1201c3e09182SJohn Daley 	 */
1202c3e09182SJohn Daley 	if (!enic->rte_dev->data->dev_conf.rxmode.enable_scatter) {
1203c3e09182SJohn Daley 		eth_dev->data->mtu = new_mtu;
1204c3e09182SJohn Daley 		goto set_mtu_done;
1205c3e09182SJohn Daley 	}
1206c3e09182SJohn Daley 
1207c3e09182SJohn Daley 	/* Rx scatter is enabled so reconfigure RQ's on the fly. The point is to
1208c3e09182SJohn Daley 	 * change Rx scatter mode if necessary for better performance. I.e. if
1209c3e09182SJohn Daley 	 * MTU was greater than the mbuf size and now it's less, scatter Rx
1210c3e09182SJohn Daley 	 * doesn't have to be used and vice versa.
1211c3e09182SJohn Daley 	  */
1212c3e09182SJohn Daley 	rte_spinlock_lock(&enic->mtu_lock);
1213c3e09182SJohn Daley 
1214c3e09182SJohn Daley 	/* Stop traffic on all RQs */
1215c3e09182SJohn Daley 	for (rq_idx = 0; rq_idx < enic->rq_count * 2; rq_idx++) {
1216c3e09182SJohn Daley 		rq = &enic->rq[rq_idx];
1217c3e09182SJohn Daley 		if (rq->is_sop && rq->in_use) {
1218aa07bf8fSJohn Daley 			rc = enic_stop_rq(enic,
1219aa07bf8fSJohn Daley 					  enic_sop_rq_idx_to_rte_idx(rq_idx));
1220c3e09182SJohn Daley 			if (rc) {
1221c3e09182SJohn Daley 				dev_err(enic, "Failed to stop Rq %u\n", rq_idx);
1222c3e09182SJohn Daley 				goto set_mtu_done;
1223c3e09182SJohn Daley 			}
1224c3e09182SJohn Daley 		}
1225c3e09182SJohn Daley 	}
1226c3e09182SJohn Daley 
1227c3e09182SJohn Daley 	/* replace Rx funciton with a no-op to avoid getting stale pkts */
1228c3e09182SJohn Daley 	eth_dev->rx_pkt_burst = enic_dummy_recv_pkts;
1229c3e09182SJohn Daley 	rte_mb();
1230c3e09182SJohn Daley 
1231c3e09182SJohn Daley 	/* Allow time for threads to exit the real Rx function. */
1232c3e09182SJohn Daley 	usleep(100000);
1233c3e09182SJohn Daley 
1234c3e09182SJohn Daley 	/* now it is safe to reconfigure the RQs */
1235c3e09182SJohn Daley 
1236396a6d71SJohn Daley 	/* update the mtu */
1237396a6d71SJohn Daley 	eth_dev->data->mtu = new_mtu;
1238396a6d71SJohn Daley 
1239c3e09182SJohn Daley 	/* free and reallocate RQs with the new MTU */
1240c3e09182SJohn Daley 	for (rq_idx = 0; rq_idx < enic->rq_count; rq_idx++) {
1241aa07bf8fSJohn Daley 		rq = &enic->rq[enic_rte_rq_idx_to_sop_idx(rq_idx)];
1242c3e09182SJohn Daley 
1243c3e09182SJohn Daley 		enic_free_rq(rq);
1244c3e09182SJohn Daley 		rc = enic_alloc_rq(enic, rq_idx, rq->socket_id, rq->mp,
1245ce16fd70SJohn Daley 				   rq->tot_nb_desc, rq->rx_free_thresh);
1246c3e09182SJohn Daley 		if (rc) {
1247c3e09182SJohn Daley 			dev_err(enic,
1248c3e09182SJohn Daley 				"Fatal MTU alloc error- No traffic will pass\n");
1249c3e09182SJohn Daley 			goto set_mtu_done;
1250c3e09182SJohn Daley 		}
1251c3e09182SJohn Daley 
1252c3e09182SJohn Daley 		rc = enic_reinit_rq(enic, rq_idx);
1253c3e09182SJohn Daley 		if (rc) {
1254c3e09182SJohn Daley 			dev_err(enic,
1255c3e09182SJohn Daley 				"Fatal MTU RQ reinit- No traffic will pass\n");
1256c3e09182SJohn Daley 			goto set_mtu_done;
1257c3e09182SJohn Daley 		}
1258c3e09182SJohn Daley 	}
1259c3e09182SJohn Daley 
1260c3e09182SJohn Daley 	/* put back the real receive function */
1261c3e09182SJohn Daley 	rte_mb();
1262c3e09182SJohn Daley 	eth_dev->rx_pkt_burst = enic_recv_pkts;
1263c3e09182SJohn Daley 	rte_mb();
1264c3e09182SJohn Daley 
1265c3e09182SJohn Daley 	/* restart Rx traffic */
1266c3e09182SJohn Daley 	for (rq_idx = 0; rq_idx < enic->rq_count; rq_idx++) {
1267aa07bf8fSJohn Daley 		rq = &enic->rq[enic_rte_rq_idx_to_sop_idx(rq_idx)];
1268c3e09182SJohn Daley 		if (rq->is_sop && rq->in_use)
1269c3e09182SJohn Daley 			enic_start_rq(enic, rq_idx);
1270c3e09182SJohn Daley 	}
1271c3e09182SJohn Daley 
1272c3e09182SJohn Daley set_mtu_done:
1273396a6d71SJohn Daley 	dev_info(enic, "MTU changed from %u to %u\n",  old_mtu, new_mtu);
1274c3e09182SJohn Daley 	rte_spinlock_unlock(&enic->mtu_lock);
1275c3e09182SJohn Daley 	return rc;
1276396a6d71SJohn Daley }
1277396a6d71SJohn Daley 
127872f3de30SBruce Richardson static int enic_dev_init(struct enic *enic)
127972f3de30SBruce Richardson {
128072f3de30SBruce Richardson 	int err;
128172f3de30SBruce Richardson 	struct rte_eth_dev *eth_dev = enic->rte_dev;
128272f3de30SBruce Richardson 
128372f3de30SBruce Richardson 	vnic_dev_intr_coal_timer_info_default(enic->vdev);
128472f3de30SBruce Richardson 
128572f3de30SBruce Richardson 	/* Get vNIC configuration
128672f3de30SBruce Richardson 	*/
128772f3de30SBruce Richardson 	err = enic_get_vnic_config(enic);
128872f3de30SBruce Richardson 	if (err) {
128972f3de30SBruce Richardson 		dev_err(dev, "Get vNIC configuration failed, aborting\n");
129072f3de30SBruce Richardson 		return err;
129172f3de30SBruce Richardson 	}
129272f3de30SBruce Richardson 
1293b16e60abSNelson Escobar 	/* Get available resource counts */
1294b16e60abSNelson Escobar 	enic_get_res_counts(enic);
1295b16e60abSNelson Escobar 	if (enic->conf_rq_count == 1) {
1296b16e60abSNelson Escobar 		dev_err(enic, "Running with only 1 RQ configured in the vNIC is not supported.\n");
1297b16e60abSNelson Escobar 		dev_err(enic, "Please configure 2 RQs in the vNIC for each Rx queue used by DPDK.\n");
1298b16e60abSNelson Escobar 		dev_err(enic, "See the ENIC PMD guide for more information.\n");
1299b16e60abSNelson Escobar 		return -EINVAL;
1300b16e60abSNelson Escobar 	}
1301b16e60abSNelson Escobar 
1302dfbd6a9cSJohn Daley 	/* Get the supported filters */
1303dfbd6a9cSJohn Daley 	enic_fdir_info(enic);
1304dfbd6a9cSJohn Daley 
1305*bbab3d97SJohn Daley 	eth_dev->data->mac_addrs = rte_zmalloc("enic_mac_addr", ETH_ALEN
1306*bbab3d97SJohn Daley 						* ENIC_MAX_MAC_ADDR, 0);
130772f3de30SBruce Richardson 	if (!eth_dev->data->mac_addrs) {
130872f3de30SBruce Richardson 		dev_err(enic, "mac addr storage alloc failed, aborting.\n");
130972f3de30SBruce Richardson 		return -1;
131072f3de30SBruce Richardson 	}
131172f3de30SBruce Richardson 	ether_addr_copy((struct ether_addr *) enic->mac_addr,
1312*bbab3d97SJohn Daley 			eth_dev->data->mac_addrs);
131372f3de30SBruce Richardson 
131472f3de30SBruce Richardson 	vnic_dev_set_reset_flag(enic->vdev, 0);
131572f3de30SBruce Richardson 
1316c98779abSNelson Escobar 	/* set up link status checking */
1317c98779abSNelson Escobar 	vnic_dev_notify_set(enic->vdev, -1); /* No Intr for notify */
1318c98779abSNelson Escobar 
131972f3de30SBruce Richardson 	return 0;
132072f3de30SBruce Richardson 
132172f3de30SBruce Richardson }
132272f3de30SBruce Richardson 
132372f3de30SBruce Richardson int enic_probe(struct enic *enic)
132472f3de30SBruce Richardson {
132572f3de30SBruce Richardson 	struct rte_pci_device *pdev = enic->pdev;
132672f3de30SBruce Richardson 	int err = -1;
132772f3de30SBruce Richardson 
1328d0c98d9eSJohn Daley 	dev_debug(enic, " Initializing ENIC PMD\n");
132972f3de30SBruce Richardson 
133072f3de30SBruce Richardson 	enic->bar0.vaddr = (void *)pdev->mem_resource[0].addr;
133172f3de30SBruce Richardson 	enic->bar0.len = pdev->mem_resource[0].len;
133272f3de30SBruce Richardson 
133372f3de30SBruce Richardson 	/* Register vNIC device */
133472f3de30SBruce Richardson 	enic->vdev = vnic_dev_register(NULL, enic, enic->pdev, &enic->bar0, 1);
133572f3de30SBruce Richardson 	if (!enic->vdev) {
133672f3de30SBruce Richardson 		dev_err(enic, "vNIC registration failed, aborting\n");
133772f3de30SBruce Richardson 		goto err_out;
133872f3de30SBruce Richardson 	}
133972f3de30SBruce Richardson 
1340da5f560bSNelson Escobar 	LIST_INIT(&enic->memzone_list);
1341da5f560bSNelson Escobar 	rte_spinlock_init(&enic->memzone_list_lock);
1342da5f560bSNelson Escobar 
134372f3de30SBruce Richardson 	vnic_register_cbacks(enic->vdev,
134472f3de30SBruce Richardson 		enic_alloc_consistent,
134572f3de30SBruce Richardson 		enic_free_consistent);
134672f3de30SBruce Richardson 
134772f3de30SBruce Richardson 	/* Issue device open to get device in known state */
134872f3de30SBruce Richardson 	err = enic_dev_open(enic);
134972f3de30SBruce Richardson 	if (err) {
135072f3de30SBruce Richardson 		dev_err(enic, "vNIC dev open failed, aborting\n");
135172f3de30SBruce Richardson 		goto err_out_unregister;
135272f3de30SBruce Richardson 	}
135372f3de30SBruce Richardson 
135472f3de30SBruce Richardson 	/* Set ingress vlan rewrite mode before vnic initialization */
135572f3de30SBruce Richardson 	err = vnic_dev_set_ig_vlan_rewrite_mode(enic->vdev,
1356947d860cSJohn Daley 		IG_VLAN_REWRITE_MODE_PASS_THRU);
135772f3de30SBruce Richardson 	if (err) {
135872f3de30SBruce Richardson 		dev_err(enic,
135972f3de30SBruce Richardson 			"Failed to set ingress vlan rewrite mode, aborting.\n");
136072f3de30SBruce Richardson 		goto err_out_dev_close;
136172f3de30SBruce Richardson 	}
136272f3de30SBruce Richardson 
136372f3de30SBruce Richardson 	/* Issue device init to initialize the vnic-to-switch link.
136472f3de30SBruce Richardson 	 * We'll start with carrier off and wait for link UP
136572f3de30SBruce Richardson 	 * notification later to turn on carrier.  We don't need
136672f3de30SBruce Richardson 	 * to wait here for the vnic-to-switch link initialization
136772f3de30SBruce Richardson 	 * to complete; link UP notification is the indication that
136872f3de30SBruce Richardson 	 * the process is complete.
136972f3de30SBruce Richardson 	 */
137072f3de30SBruce Richardson 
137172f3de30SBruce Richardson 	err = vnic_dev_init(enic->vdev, 0);
137272f3de30SBruce Richardson 	if (err) {
137372f3de30SBruce Richardson 		dev_err(enic, "vNIC dev init failed, aborting\n");
137472f3de30SBruce Richardson 		goto err_out_dev_close;
137572f3de30SBruce Richardson 	}
137672f3de30SBruce Richardson 
137772f3de30SBruce Richardson 	err = enic_dev_init(enic);
137872f3de30SBruce Richardson 	if (err) {
137972f3de30SBruce Richardson 		dev_err(enic, "Device initialization failed, aborting\n");
138072f3de30SBruce Richardson 		goto err_out_dev_close;
138172f3de30SBruce Richardson 	}
138272f3de30SBruce Richardson 
138372f3de30SBruce Richardson 	return 0;
138472f3de30SBruce Richardson 
138572f3de30SBruce Richardson err_out_dev_close:
138672f3de30SBruce Richardson 	vnic_dev_close(enic->vdev);
138772f3de30SBruce Richardson err_out_unregister:
138872f3de30SBruce Richardson 	vnic_dev_unregister(enic->vdev);
138972f3de30SBruce Richardson err_out:
139072f3de30SBruce Richardson 	return err;
139172f3de30SBruce Richardson }
139272f3de30SBruce Richardson 
139372f3de30SBruce Richardson void enic_remove(struct enic *enic)
139472f3de30SBruce Richardson {
139572f3de30SBruce Richardson 	enic_dev_deinit(enic);
139672f3de30SBruce Richardson 	vnic_dev_close(enic->vdev);
139772f3de30SBruce Richardson 	vnic_dev_unregister(enic->vdev);
139872f3de30SBruce Richardson }
1399