xref: /linux/drivers/net/ethernet/cisco/enic/enic_admin.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
13258931dSSatish Kharat // SPDX-License-Identifier: GPL-2.0-only
23258931dSSatish Kharat // Copyright 2025 Cisco Systems, Inc.  All rights reserved.
33258931dSSatish Kharat 
43258931dSSatish Kharat #include <linux/kernel.h>
53258931dSSatish Kharat #include <linux/netdevice.h>
6a0da4ea7SSatish Kharat #include <linux/dma-mapping.h>
7cb1dba54SSatish Kharat #include <linux/interrupt.h>
83258931dSSatish Kharat 
93258931dSSatish Kharat #include "vnic_dev.h"
103258931dSSatish Kharat #include "vnic_wq.h"
113258931dSSatish Kharat #include "vnic_rq.h"
123258931dSSatish Kharat #include "vnic_cq.h"
133258931dSSatish Kharat #include "vnic_intr.h"
143258931dSSatish Kharat #include "vnic_resource.h"
153258931dSSatish Kharat #include "vnic_devcmd.h"
163258931dSSatish Kharat #include "enic.h"
173258931dSSatish Kharat #include "enic_admin.h"
183258931dSSatish Kharat #include "cq_desc.h"
19cb1dba54SSatish Kharat #include "cq_enet_desc.h"
203258931dSSatish Kharat #include "wq_enet_desc.h"
213258931dSSatish Kharat #include "rq_enet_desc.h"
221f0c856bSSatish Kharat #include "enic_mbox.h"
233258931dSSatish Kharat 
24cb1dba54SSatish Kharat /* Retry interval for a failed admin RQ refill.  Short so the control
25cb1dba54SSatish Kharat  * channel recovers quickly once memory is available again.
26cb1dba54SSatish Kharat  */
27cb1dba54SSatish Kharat #define ENIC_ADMIN_RQ_REFILL_RETRY_MS	100
28cb1dba54SSatish Kharat 
293258931dSSatish Kharat /* Clean up any admin WQ buffers still held by hardware at close time.
303258931dSSatish Kharat  * Normally buffers are freed inline after send completion, but a timed-out
313258931dSSatish Kharat  * send intentionally leaves the buffer live until the queue is stopped.
323258931dSSatish Kharat  */
enic_admin_wq_buf_clean(struct vnic_wq * wq,struct vnic_wq_buf * buf)333258931dSSatish Kharat static void enic_admin_wq_buf_clean(struct vnic_wq *wq,
343258931dSSatish Kharat 				    struct vnic_wq_buf *buf)
353258931dSSatish Kharat {
363258931dSSatish Kharat 	struct enic *enic = vnic_dev_priv(wq->vdev);
373258931dSSatish Kharat 
383258931dSSatish Kharat 	if (buf->os_buf) {
393258931dSSatish Kharat 		dma_unmap_single(&enic->pdev->dev, buf->dma_addr,
403258931dSSatish Kharat 				 buf->len, DMA_TO_DEVICE);
413258931dSSatish Kharat 		kfree(buf->os_buf);
423258931dSSatish Kharat 		buf->os_buf = NULL;
433258931dSSatish Kharat 	}
443258931dSSatish Kharat }
453258931dSSatish Kharat 
enic_admin_rq_buf_clean(struct vnic_rq * rq,struct vnic_rq_buf * buf)463258931dSSatish Kharat static void enic_admin_rq_buf_clean(struct vnic_rq *rq,
473258931dSSatish Kharat 				    struct vnic_rq_buf *buf)
483258931dSSatish Kharat {
49a0da4ea7SSatish Kharat 	struct enic *enic = vnic_dev_priv(rq->vdev);
50a0da4ea7SSatish Kharat 
51a0da4ea7SSatish Kharat 	if (!buf->os_buf)
52a0da4ea7SSatish Kharat 		return;
53a0da4ea7SSatish Kharat 
54a0da4ea7SSatish Kharat 	dma_unmap_single(&enic->pdev->dev, buf->dma_addr, buf->len,
55a0da4ea7SSatish Kharat 			 DMA_FROM_DEVICE);
56a0da4ea7SSatish Kharat 	kfree(buf->os_buf);
57a0da4ea7SSatish Kharat 	buf->os_buf = NULL;
58a0da4ea7SSatish Kharat }
59a0da4ea7SSatish Kharat 
enic_admin_rq_post_one(struct enic * enic,gfp_t gfp)60a0da4ea7SSatish Kharat static int enic_admin_rq_post_one(struct enic *enic, gfp_t gfp)
61a0da4ea7SSatish Kharat {
62a0da4ea7SSatish Kharat 	struct vnic_rq *rq = &enic->admin_rq;
63a0da4ea7SSatish Kharat 	struct rq_enet_desc *desc;
64a0da4ea7SSatish Kharat 	dma_addr_t dma_addr;
65a0da4ea7SSatish Kharat 	void *buf;
66a0da4ea7SSatish Kharat 
67a0da4ea7SSatish Kharat 	buf = kzalloc(ENIC_ADMIN_BUF_SIZE, gfp);
68a0da4ea7SSatish Kharat 	if (!buf)
69a0da4ea7SSatish Kharat 		return -ENOMEM;
70a0da4ea7SSatish Kharat 
71a0da4ea7SSatish Kharat 	dma_addr = dma_map_single(&enic->pdev->dev, buf, ENIC_ADMIN_BUF_SIZE,
72a0da4ea7SSatish Kharat 				  DMA_FROM_DEVICE);
73a0da4ea7SSatish Kharat 	if (dma_mapping_error(&enic->pdev->dev, dma_addr)) {
74a0da4ea7SSatish Kharat 		kfree(buf);
75a0da4ea7SSatish Kharat 		return -ENOMEM;
76a0da4ea7SSatish Kharat 	}
77a0da4ea7SSatish Kharat 
78a0da4ea7SSatish Kharat 	desc = vnic_rq_next_desc(rq);
79a0da4ea7SSatish Kharat 	rq_enet_desc_enc(desc, (u64)dma_addr | VNIC_PADDR_TARGET,
80a0da4ea7SSatish Kharat 			 RQ_ENET_TYPE_ONLY_SOP, ENIC_ADMIN_BUF_SIZE);
81a0da4ea7SSatish Kharat 	vnic_rq_post(rq, buf, 0, dma_addr, ENIC_ADMIN_BUF_SIZE, 0);
82a0da4ea7SSatish Kharat 
83a0da4ea7SSatish Kharat 	return 0;
84a0da4ea7SSatish Kharat }
85a0da4ea7SSatish Kharat 
enic_admin_rq_fill(struct enic * enic,gfp_t gfp)86a0da4ea7SSatish Kharat static int enic_admin_rq_fill(struct enic *enic, gfp_t gfp)
87a0da4ea7SSatish Kharat {
88a0da4ea7SSatish Kharat 	struct vnic_rq *rq = &enic->admin_rq;
89a0da4ea7SSatish Kharat 	int err;
90a0da4ea7SSatish Kharat 
91a0da4ea7SSatish Kharat 	while (vnic_rq_desc_avail(rq) > 0) {
92a0da4ea7SSatish Kharat 		err = enic_admin_rq_post_one(enic, gfp);
93a0da4ea7SSatish Kharat 		if (err)
94a0da4ea7SSatish Kharat 			return err;
95a0da4ea7SSatish Kharat 	}
96a0da4ea7SSatish Kharat 
97a0da4ea7SSatish Kharat 	return 0;
98a0da4ea7SSatish Kharat }
99a0da4ea7SSatish Kharat 
enic_admin_rq_drain(struct enic * enic)100a0da4ea7SSatish Kharat static void enic_admin_rq_drain(struct enic *enic)
101a0da4ea7SSatish Kharat {
102a0da4ea7SSatish Kharat 	vnic_rq_clean(&enic->admin_rq, enic_admin_rq_buf_clean);
1033258931dSSatish Kharat }
1043258931dSSatish Kharat 
enic_admin_cq_color(void * cq_desc,unsigned int desc_size)105cb1dba54SSatish Kharat static unsigned int enic_admin_cq_color(void *cq_desc, unsigned int desc_size)
106cb1dba54SSatish Kharat {
107cb1dba54SSatish Kharat 	u8 type_color = *((u8 *)cq_desc + desc_size - 1);
108cb1dba54SSatish Kharat 
109cb1dba54SSatish Kharat 	return (type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK;
110cb1dba54SSatish Kharat }
111cb1dba54SSatish Kharat 
enic_admin_wq_cq_service(struct enic * enic)112cb1dba54SSatish Kharat unsigned int enic_admin_wq_cq_service(struct enic *enic)
113cb1dba54SSatish Kharat {
114cb1dba54SSatish Kharat 	struct vnic_cq *cq = &enic->admin_cq[0];
115cb1dba54SSatish Kharat 	unsigned int work = 0;
116cb1dba54SSatish Kharat 	void *desc;
117cb1dba54SSatish Kharat 
118cb1dba54SSatish Kharat 	desc = vnic_cq_to_clean(cq);
119cb1dba54SSatish Kharat 	while (enic_admin_cq_color(desc, cq->ring.desc_size) !=
120cb1dba54SSatish Kharat 	       cq->last_color) {
121cb1dba54SSatish Kharat 		vnic_cq_inc_to_clean(cq);
122cb1dba54SSatish Kharat 		work++;
123cb1dba54SSatish Kharat 		desc = vnic_cq_to_clean(cq);
124cb1dba54SSatish Kharat 	}
125cb1dba54SSatish Kharat 
126cb1dba54SSatish Kharat 	return work;
127cb1dba54SSatish Kharat }
128cb1dba54SSatish Kharat 
129cb1dba54SSatish Kharat /* Upper bound on pending admin messages.  A buggy or hostile VF could flood
130cb1dba54SSatish Kharat  * the PF admin channel faster than admin_msg_work drains it; cap the backlog
131cb1dba54SSatish Kharat  * so a guest cannot drive the host out of memory.
132cb1dba54SSatish Kharat  */
133cb1dba54SSatish Kharat #define ENIC_ADMIN_MSG_MAX	256
134cb1dba54SSatish Kharat 
enic_admin_msg_enqueue(struct enic * enic,void * buf,unsigned int len)135cb1dba54SSatish Kharat static void enic_admin_msg_enqueue(struct enic *enic, void *buf,
136cb1dba54SSatish Kharat 				   unsigned int len)
137cb1dba54SSatish Kharat {
138cb1dba54SSatish Kharat 	struct enic_admin_msg *msg;
139cb1dba54SSatish Kharat 
140cb1dba54SSatish Kharat 	msg = kmalloc(struct_size(msg, data, len), GFP_KERNEL);
141cb1dba54SSatish Kharat 	if (!msg)
142cb1dba54SSatish Kharat 		return;
143cb1dba54SSatish Kharat 
144cb1dba54SSatish Kharat 	msg->len = len;
145cb1dba54SSatish Kharat 	memcpy(msg->data, buf, len);
146cb1dba54SSatish Kharat 
147cb1dba54SSatish Kharat 	spin_lock(&enic->admin_msg_lock);
148cb1dba54SSatish Kharat 	if (enic->admin_msg_count >= ENIC_ADMIN_MSG_MAX) {
149cb1dba54SSatish Kharat 		spin_unlock(&enic->admin_msg_lock);
150cb1dba54SSatish Kharat 		kfree(msg);
151cb1dba54SSatish Kharat 		if (net_ratelimit())
152cb1dba54SSatish Kharat 			netdev_warn(enic->netdev,
153cb1dba54SSatish Kharat 				    "admin msg backlog full (%u); dropping\n",
154cb1dba54SSatish Kharat 				    ENIC_ADMIN_MSG_MAX);
155cb1dba54SSatish Kharat 		return;
156cb1dba54SSatish Kharat 	}
157cb1dba54SSatish Kharat 	list_add_tail(&msg->list, &enic->admin_msg_list);
158cb1dba54SSatish Kharat 	enic->admin_msg_count++;
159cb1dba54SSatish Kharat 	spin_unlock(&enic->admin_msg_lock);
160cb1dba54SSatish Kharat }
161cb1dba54SSatish Kharat 
enic_admin_rq_cq_service(struct enic * enic)162cb1dba54SSatish Kharat unsigned int enic_admin_rq_cq_service(struct enic *enic)
163cb1dba54SSatish Kharat {
164cb1dba54SSatish Kharat 	struct vnic_cq *cq = &enic->admin_cq[1];
165cb1dba54SSatish Kharat 	struct vnic_rq *rq = &enic->admin_rq;
166cb1dba54SSatish Kharat 	struct cq_enet_rq_desc *rq_desc;
167cb1dba54SSatish Kharat 	struct vnic_rq_buf *buf;
168cb1dba54SSatish Kharat 	u16 bwf, bytes_written;
169cb1dba54SSatish Kharat 	unsigned int work = 0;
170cb1dba54SSatish Kharat 	void *desc;
171cb1dba54SSatish Kharat 
172cb1dba54SSatish Kharat 	/* The admin RQ and its CQ form a single in-order channel: firmware
173cb1dba54SSatish Kharat 	 * posts exactly one CQE per consumed RQ descriptor, in submission
174cb1dba54SSatish Kharat 	 * order.  Each CQE therefore pairs with rq->to_clean below without a
175cb1dba54SSatish Kharat 	 * completed_index cross-check, mirroring the in-order assumption of
176cb1dba54SSatish Kharat 	 * the main enic RX path.
177cb1dba54SSatish Kharat 	 */
178cb1dba54SSatish Kharat 	desc = vnic_cq_to_clean(cq);
179cb1dba54SSatish Kharat 	while (enic_admin_cq_color(desc, cq->ring.desc_size) !=
180cb1dba54SSatish Kharat 	       cq->last_color) {
181cb1dba54SSatish Kharat 		/* Ensure DMA descriptor fields are read after
182cb1dba54SSatish Kharat 		 * the color/valid check.  dma_rmb() is the
183cb1dba54SSatish Kharat 		 * correct barrier for DMA-written descriptors.
184cb1dba54SSatish Kharat 		 */
185cb1dba54SSatish Kharat 		dma_rmb();
186cb1dba54SSatish Kharat 		buf = rq->to_clean;
187cb1dba54SSatish Kharat 
188cb1dba54SSatish Kharat 		/* Decode the actual number of bytes hardware wrote into
189cb1dba54SSatish Kharat 		 * the RX buffer.  buf->len is the static allocation size
190cb1dba54SSatish Kharat 		 * (ENIC_ADMIN_BUF_SIZE); copying that many bytes would read
191cb1dba54SSatish Kharat 		 * beyond the actual DMA payload.  bytes_written_flags is at
192cb1dba54SSatish Kharat 		 * the same offset in every cq_enet_rq_desc[_32|_64] variant.
193cb1dba54SSatish Kharat 		 */
194cb1dba54SSatish Kharat 		rq_desc = desc;
195cb1dba54SSatish Kharat 		bwf = le16_to_cpu(rq_desc->bytes_written_flags);
196cb1dba54SSatish Kharat 		bytes_written = bwf & CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK;
197cb1dba54SSatish Kharat 		if (bytes_written > buf->len)
198cb1dba54SSatish Kharat 			goto next_desc;
199cb1dba54SSatish Kharat 
200cb1dba54SSatish Kharat 		dma_sync_single_for_cpu(&enic->pdev->dev,
201cb1dba54SSatish Kharat 					buf->dma_addr, buf->len,
202cb1dba54SSatish Kharat 					DMA_FROM_DEVICE);
203cb1dba54SSatish Kharat 
204cb1dba54SSatish Kharat 		/* Drop on hardware error indications.  Admin messages
205cb1dba54SSatish Kharat 		 * are internal to the VIC, not received over the wire.
206cb1dba54SSatish Kharat 		 * Firmware sets TRUNCATED when the message does not fit
207cb1dba54SSatish Kharat 		 * in the posted buffer, and FCS_OK is always set on
208cb1dba54SSatish Kharat 		 * healthy admin completions.
209cb1dba54SSatish Kharat 		 */
210cb1dba54SSatish Kharat 		if (bwf & CQ_ENET_RQ_DESC_FLAGS_TRUNCATED) {
211cb1dba54SSatish Kharat 			netdev_warn_once(enic->netdev,
212cb1dba54SSatish Kharat 					 "admin RQ: truncated message dropped\n");
213cb1dba54SSatish Kharat 			goto next_desc;
214cb1dba54SSatish Kharat 		}
215cb1dba54SSatish Kharat 		if (!(rq_desc->flags & CQ_ENET_RQ_DESC_FLAGS_FCS_OK)) {
216cb1dba54SSatish Kharat 			netdev_warn_once(enic->netdev,
217cb1dba54SSatish Kharat 					 "admin RQ: bad FCS, dropping message\n");
218cb1dba54SSatish Kharat 			goto next_desc;
219cb1dba54SSatish Kharat 		}
220cb1dba54SSatish Kharat 
2211f0c856bSSatish Kharat 		if (enic->admin_rq_handler) {
2221f0c856bSSatish Kharat 			u16 sender_vlan;
2231f0c856bSSatish Kharat 
2241f0c856bSSatish Kharat 			/* Firmware sets the CQ VLAN field to identify the
2251f0c856bSSatish Kharat 			 * sender: 0 = PF, 1-based = VF index.  Overwrite
2261f0c856bSSatish Kharat 			 * the untrusted src_vnic_id in the MBOX header with
2271f0c856bSSatish Kharat 			 * the hardware-verified value.
2281f0c856bSSatish Kharat 			 */
2291f0c856bSSatish Kharat 			sender_vlan = le16_to_cpu(rq_desc->vlan);
2301f0c856bSSatish Kharat 			if (bytes_written >= sizeof(struct enic_mbox_hdr)) {
2311f0c856bSSatish Kharat 				struct enic_mbox_hdr *hdr = buf->os_buf;
2321f0c856bSSatish Kharat 
2331f0c856bSSatish Kharat 				hdr->src_vnic_id = (sender_vlan == 0) ?
2341f0c856bSSatish Kharat 					cpu_to_le16(ENIC_MBOX_DST_PF) :
2351f0c856bSSatish Kharat 					cpu_to_le16(sender_vlan - 1);
2361f0c856bSSatish Kharat 			}
2371f0c856bSSatish Kharat 
2381f0c856bSSatish Kharat 			enic_admin_msg_enqueue(enic, buf->os_buf,
2391f0c856bSSatish Kharat 					       bytes_written);
2401f0c856bSSatish Kharat 		}
241cb1dba54SSatish Kharat 
242cb1dba54SSatish Kharat next_desc:
243cb1dba54SSatish Kharat 		enic_admin_rq_buf_clean(rq, rq->to_clean);
244cb1dba54SSatish Kharat 		rq->to_clean = rq->to_clean->next;
245cb1dba54SSatish Kharat 		rq->ring.desc_avail++;
246cb1dba54SSatish Kharat 
247cb1dba54SSatish Kharat 		vnic_cq_inc_to_clean(cq);
248cb1dba54SSatish Kharat 		work++;
249cb1dba54SSatish Kharat 		desc = vnic_cq_to_clean(cq);
250cb1dba54SSatish Kharat 	}
251cb1dba54SSatish Kharat 
252cb1dba54SSatish Kharat 	if (enic_admin_rq_fill(enic, GFP_KERNEL)) {
253cb1dba54SSatish Kharat 		/* Some RX buffers could not be reposted (transient memory
254cb1dba54SSatish Kharat 		 * pressure).  If the ring is left empty the channel would stall
255cb1dba54SSatish Kharat 		 * with no completion to drive the next refill, so arm a delayed
256cb1dba54SSatish Kharat 		 * re-run of this poll work (the sole owner of the admin RQ ring)
257cb1dba54SSatish Kharat 		 * to repost buffers and re-arm the RQ from a single context.
258cb1dba54SSatish Kharat 		 */
259cb1dba54SSatish Kharat 		if (net_ratelimit())
260cb1dba54SSatish Kharat 			netdev_warn(enic->netdev,
261cb1dba54SSatish Kharat 				    "admin RQ refill failed; scheduling retry\n");
262cb1dba54SSatish Kharat 		schedule_delayed_work(&enic->admin_poll_work,
263cb1dba54SSatish Kharat 				      msecs_to_jiffies(ENIC_ADMIN_RQ_REFILL_RETRY_MS));
264cb1dba54SSatish Kharat 	}
265cb1dba54SSatish Kharat 
266cb1dba54SSatish Kharat 	return work;
267cb1dba54SSatish Kharat }
268cb1dba54SSatish Kharat 
enic_admin_isr_msix(int irq,void * data)269cb1dba54SSatish Kharat static irqreturn_t enic_admin_isr_msix(int irq, void *data)
270cb1dba54SSatish Kharat {
271cb1dba54SSatish Kharat 	struct enic *enic = data;
272cb1dba54SSatish Kharat 
273cb1dba54SSatish Kharat 	schedule_delayed_work(&enic->admin_poll_work, 0);
274cb1dba54SSatish Kharat 
275cb1dba54SSatish Kharat 	return IRQ_HANDLED;
276cb1dba54SSatish Kharat }
277cb1dba54SSatish Kharat 
enic_admin_msg_work_handler(struct work_struct * work)278cb1dba54SSatish Kharat static void enic_admin_msg_work_handler(struct work_struct *work)
279cb1dba54SSatish Kharat {
280cb1dba54SSatish Kharat 	struct enic *enic = container_of(work, struct enic, admin_msg_work);
281cb1dba54SSatish Kharat 	struct enic_admin_msg *msg, *tmp;
282cb1dba54SSatish Kharat 	LIST_HEAD(local_list);
283cb1dba54SSatish Kharat 
284cb1dba54SSatish Kharat 	spin_lock_bh(&enic->admin_msg_lock);
285cb1dba54SSatish Kharat 	list_splice_init(&enic->admin_msg_list, &local_list);
286cb1dba54SSatish Kharat 	enic->admin_msg_count = 0;
287cb1dba54SSatish Kharat 	spin_unlock_bh(&enic->admin_msg_lock);
288cb1dba54SSatish Kharat 
289cb1dba54SSatish Kharat 	list_for_each_entry_safe(msg, tmp, &local_list, list) {
290cb1dba54SSatish Kharat 		if (enic->admin_rq_handler)
291cb1dba54SSatish Kharat 			enic->admin_rq_handler(enic, msg->data, msg->len);
292cb1dba54SSatish Kharat 		list_del(&msg->list);
293cb1dba54SSatish Kharat 		kfree(msg);
294cb1dba54SSatish Kharat 	}
295cb1dba54SSatish Kharat }
296cb1dba54SSatish Kharat 
enic_admin_poll_work_handler(struct work_struct * work)297cb1dba54SSatish Kharat static void enic_admin_poll_work_handler(struct work_struct *work)
298cb1dba54SSatish Kharat {
299cb1dba54SSatish Kharat 	struct enic *enic = container_of(to_delayed_work(work), struct enic,
300cb1dba54SSatish Kharat 					 admin_poll_work);
301cb1dba54SSatish Kharat 	unsigned int credits;
302cb1dba54SSatish Kharat 	unsigned int rq_work;
303cb1dba54SSatish Kharat 
304cb1dba54SSatish Kharat 	/* Snapshot the pending credit count before draining so we acknowledge
305cb1dba54SSatish Kharat 	 * exactly what the hardware reported for this interrupt.  Credits that
306cb1dba54SSatish Kharat 	 * accrue while enic_admin_rq_cq_service() runs are left for the next
307cb1dba54SSatish Kharat 	 * interrupt, which is harmless on this low-rate control path.
308cb1dba54SSatish Kharat 	 */
309cb1dba54SSatish Kharat 	credits = vnic_intr_credits(&enic->admin_intr);
310cb1dba54SSatish Kharat 
311cb1dba54SSatish Kharat 	rq_work = enic_admin_rq_cq_service(enic);
312cb1dba54SSatish Kharat 
313cb1dba54SSatish Kharat 	if (rq_work > 0)
314cb1dba54SSatish Kharat 		schedule_work(&enic->admin_msg_work);
315cb1dba54SSatish Kharat 
316cb1dba54SSatish Kharat 	/* Acknowledge the snapshotted credits and unmask the vector.  Unlike
317cb1dba54SSatish Kharat 	 * the NAPI data path, the admin channel is not re-polled, so the vector
318cb1dba54SSatish Kharat 	 * must be re-armed here to receive the next completion.  The unmask is
319cb1dba54SSatish Kharat 	 * applied through the interrupt mask register independently of the
320cb1dba54SSatish Kharat 	 * credit count, so returning zero credits on a spurious wakeup still
321cb1dba54SSatish Kharat 	 * re-arms the vector.
322cb1dba54SSatish Kharat 	 */
323cb1dba54SSatish Kharat 	vnic_intr_return_credits(&enic->admin_intr,
324cb1dba54SSatish Kharat 				 credits,
325cb1dba54SSatish Kharat 				 1 /* unmask */, 0);
326cb1dba54SSatish Kharat }
327cb1dba54SSatish Kharat 
enic_admin_setup_intr(struct enic * enic)328cb1dba54SSatish Kharat static int enic_admin_setup_intr(struct enic *enic)
329cb1dba54SSatish Kharat {
330cb1dba54SSatish Kharat 	unsigned int intr_index = enic->intr_count;
331cb1dba54SSatish Kharat 	int err;
332cb1dba54SSatish Kharat 
333cb1dba54SSatish Kharat 	if (vnic_dev_get_intr_mode(enic->vdev) != VNIC_DEV_INTR_MODE_MSIX ||
334cb1dba54SSatish Kharat 	    intr_index >= enic->intr_avail)
335cb1dba54SSatish Kharat 		return -ENODEV;
336cb1dba54SSatish Kharat 
337cb1dba54SSatish Kharat 	/* The admin INTR uses a slot in the same RES_TYPE_INTR_CTRL
338cb1dba54SSatish Kharat 	 * strided array of per-vector control blocks (mask, coalescing
339cb1dba54SSatish Kharat 	 * timer, credit return) that the data-path IRQs occupy in BAR0.
340cb1dba54SSatish Kharat 	 * vnic_intr_alloc() defaults to RES_TYPE_INTR_CTRL, which is what
341cb1dba54SSatish Kharat 	 * we want here.
342cb1dba54SSatish Kharat 	 */
343cb1dba54SSatish Kharat 	err = vnic_intr_alloc(enic->vdev, &enic->admin_intr, intr_index);
344cb1dba54SSatish Kharat 	if (err) {
345cb1dba54SSatish Kharat 		netdev_warn(enic->netdev,
346cb1dba54SSatish Kharat 			    "Failed to alloc admin intr at index %u: %d\n",
347cb1dba54SSatish Kharat 			    intr_index, err);
348cb1dba54SSatish Kharat 		return err;
349cb1dba54SSatish Kharat 	}
350cb1dba54SSatish Kharat 
351cb1dba54SSatish Kharat 	enic->admin_intr_index = intr_index;
352cb1dba54SSatish Kharat 
353cb1dba54SSatish Kharat 	/* Mask the admin vector before requesting the IRQ so an early or
354cb1dba54SSatish Kharat 	 * spurious completion cannot run the poll handler against the
355cb1dba54SSatish Kharat 	 * not-yet-initialised admin rings.  enic_admin_channel_open() unmasks
356cb1dba54SSatish Kharat 	 * it only after the rings are initialised and filled.
357cb1dba54SSatish Kharat 	 */
358cb1dba54SSatish Kharat 	vnic_intr_mask(&enic->admin_intr);
359cb1dba54SSatish Kharat 
360cb1dba54SSatish Kharat 	/* A V2 VF opens the admin channel during probe, before
361cb1dba54SSatish Kharat 	 * register_netdev() resolves the "eth%d" name template, so using
362cb1dba54SSatish Kharat 	 * netdev->name here would register the literal "eth%d-admin" in
363cb1dba54SSatish Kharat 	 * /proc/interrupts.  Use the already-stable PCI device name instead.
364cb1dba54SSatish Kharat 	 */
365cb1dba54SSatish Kharat 	snprintf(enic->msix[intr_index].devname,
366cb1dba54SSatish Kharat 		 sizeof(enic->msix[intr_index].devname),
367cb1dba54SSatish Kharat 		 "%s-admin", pci_name(enic->pdev));
368cb1dba54SSatish Kharat 	enic->msix[intr_index].isr = enic_admin_isr_msix;
369cb1dba54SSatish Kharat 	enic->msix[intr_index].devid = enic;
370cb1dba54SSatish Kharat 
371cb1dba54SSatish Kharat 	err = request_irq(enic->msix_entry[intr_index].vector,
372cb1dba54SSatish Kharat 			  enic->msix[intr_index].isr, 0,
373cb1dba54SSatish Kharat 			  enic->msix[intr_index].devname,
374cb1dba54SSatish Kharat 			  enic->msix[intr_index].devid);
375cb1dba54SSatish Kharat 	if (err) {
376cb1dba54SSatish Kharat 		netdev_warn(enic->netdev,
377cb1dba54SSatish Kharat 			    "Failed to request admin MSI-X irq: %d\n", err);
378cb1dba54SSatish Kharat 		vnic_intr_free(&enic->admin_intr);
379cb1dba54SSatish Kharat 		return err;
380cb1dba54SSatish Kharat 	}
381cb1dba54SSatish Kharat 
382cb1dba54SSatish Kharat 	enic->msix[intr_index].requested = 1;
383cb1dba54SSatish Kharat 
384cb1dba54SSatish Kharat 	netdev_dbg(enic->netdev,
385cb1dba54SSatish Kharat 		   "admin channel using MSI-X interrupt (index %u)\n",
386cb1dba54SSatish Kharat 		   intr_index);
387cb1dba54SSatish Kharat 
388cb1dba54SSatish Kharat 	return 0;
389cb1dba54SSatish Kharat }
390cb1dba54SSatish Kharat 
enic_admin_teardown_intr(struct enic * enic)391cb1dba54SSatish Kharat static void enic_admin_teardown_intr(struct enic *enic)
392cb1dba54SSatish Kharat {
393cb1dba54SSatish Kharat 	unsigned int intr_index = enic->admin_intr_index;
394cb1dba54SSatish Kharat 
395cb1dba54SSatish Kharat 	free_irq(enic->msix_entry[intr_index].vector,
396cb1dba54SSatish Kharat 		 enic->msix[intr_index].devid);
397cb1dba54SSatish Kharat 	cancel_delayed_work_sync(&enic->admin_poll_work);
398cb1dba54SSatish Kharat 	enic->msix[intr_index].requested = 0;
399cb1dba54SSatish Kharat }
400cb1dba54SSatish Kharat 
enic_admin_qp_type_set(struct enic * enic,u32 enable)4013258931dSSatish Kharat static int enic_admin_qp_type_set(struct enic *enic, u32 enable)
4023258931dSSatish Kharat {
4033258931dSSatish Kharat 	u64 a0 = QP_TYPE_ADMIN, a1 = enable;
4043258931dSSatish Kharat 	int wait = 1000;
4053258931dSSatish Kharat 	int err;
4063258931dSSatish Kharat 
4073258931dSSatish Kharat 	spin_lock_bh(&enic->devcmd_lock);
4083258931dSSatish Kharat 	err = vnic_dev_cmd(enic->vdev, CMD_QP_TYPE_SET, &a0, &a1, wait);
4093258931dSSatish Kharat 	spin_unlock_bh(&enic->devcmd_lock);
4103258931dSSatish Kharat 
4113258931dSSatish Kharat 	return err;
4123258931dSSatish Kharat }
4133258931dSSatish Kharat 
enic_admin_alloc_resources(struct enic * enic)4143258931dSSatish Kharat static int enic_admin_alloc_resources(struct enic *enic)
4153258931dSSatish Kharat {
4163258931dSSatish Kharat 	int err;
4173258931dSSatish Kharat 
4183258931dSSatish Kharat 	err = vnic_wq_alloc_with_type(enic->vdev, &enic->admin_wq, 0,
4193258931dSSatish Kharat 				      ENIC_ADMIN_DESC_COUNT,
4203258931dSSatish Kharat 				      sizeof(struct wq_enet_desc),
4213258931dSSatish Kharat 				      RES_TYPE_ADMIN_WQ);
4223258931dSSatish Kharat 	if (err)
4233258931dSSatish Kharat 		return err;
4243258931dSSatish Kharat 
4253258931dSSatish Kharat 	err = vnic_rq_alloc_with_type(enic->vdev, &enic->admin_rq, 0,
4263258931dSSatish Kharat 				      ENIC_ADMIN_DESC_COUNT,
4273258931dSSatish Kharat 				      sizeof(struct rq_enet_desc),
4283258931dSSatish Kharat 				      RES_TYPE_ADMIN_RQ);
4293258931dSSatish Kharat 	if (err)
4303258931dSSatish Kharat 		goto free_wq;
4313258931dSSatish Kharat 
4323258931dSSatish Kharat 	/* admin_cq[0] is the WQ completion queue.  WQ CQEs are always
4333258931dSSatish Kharat 	 * 16 bytes wide; firmware always writes 16-byte CQEs for WQ
4343258931dSSatish Kharat 	 * completions on every WQ, including the admin channel WQ.
4353258931dSSatish Kharat 	 * Use sizeof(struct cq_desc) accordingly.
4363258931dSSatish Kharat 	 */
4373258931dSSatish Kharat 	err = vnic_cq_alloc_with_type(enic->vdev, &enic->admin_cq[0], 0,
4383258931dSSatish Kharat 				      ENIC_ADMIN_DESC_COUNT,
4393258931dSSatish Kharat 				      sizeof(struct cq_desc),
4403258931dSSatish Kharat 				      RES_TYPE_ADMIN_CQ);
4413258931dSSatish Kharat 	if (err)
4423258931dSSatish Kharat 		goto free_rq;
4433258931dSSatish Kharat 
4443258931dSSatish Kharat 	/* admin_cq[1] is the RQ completion queue.  Its descriptor size
4453258931dSSatish Kharat 	 * must match what firmware writes.  enic_ext_cq() called earlier
4463258931dSSatish Kharat 	 * in probe issues CMD_CQ_ENTRY_SIZE_SET for VNIC_RQ_ALL,
4473258931dSSatish Kharat 	 * programming firmware to write CQ entries of (16 << enic->ext_cq)
4483258931dSSatish Kharat 	 * bytes for every RQ CQ on the vNIC, including the admin RQ CQ.
4493258931dSSatish Kharat 	 * Allocating with the same size keeps the host poller and
4503258931dSSatish Kharat 	 * firmware in lockstep:
4513258931dSSatish Kharat 	 *
4523258931dSSatish Kharat 	 *   - The color/valid bit lives at byte (desc_size - 1) of every
4533258931dSSatish Kharat 	 *     cq_enet_rq_desc[_32|_64] variant, so enic_admin_cq_color()
4543258931dSSatish Kharat 	 *     reads it from the correct offset.
4553258931dSSatish Kharat 	 *   - Only the first 15 bytes of the descriptor (vlan,
4563258931dSSatish Kharat 	 *     bytes_written_flags, ...) are accessed by the admin path;
4573258931dSSatish Kharat 	 *     these fields are identical across all three variants (see
4583258931dSSatish Kharat 	 *     comment in enic_rq.c above cq_enet_rq_desc_dec()).
4593258931dSSatish Kharat 	 */
4603258931dSSatish Kharat 	err = vnic_cq_alloc_with_type(enic->vdev, &enic->admin_cq[1], 1,
4613258931dSSatish Kharat 				      ENIC_ADMIN_DESC_COUNT,
4623258931dSSatish Kharat 				      16 << enic->ext_cq,
4633258931dSSatish Kharat 				      RES_TYPE_ADMIN_CQ);
4643258931dSSatish Kharat 	if (err)
4653258931dSSatish Kharat 		goto free_cq0;
4663258931dSSatish Kharat 
4673258931dSSatish Kharat 	return 0;
4683258931dSSatish Kharat 
4693258931dSSatish Kharat free_cq0:
4703258931dSSatish Kharat 	vnic_cq_free(&enic->admin_cq[0]);
4713258931dSSatish Kharat free_rq:
4723258931dSSatish Kharat 	vnic_rq_free(&enic->admin_rq);
4733258931dSSatish Kharat free_wq:
4743258931dSSatish Kharat 	vnic_wq_free(&enic->admin_wq);
4753258931dSSatish Kharat 	return err;
4763258931dSSatish Kharat }
4773258931dSSatish Kharat 
enic_admin_free_resources(struct enic * enic)4783258931dSSatish Kharat static void enic_admin_free_resources(struct enic *enic)
4793258931dSSatish Kharat {
480cb1dba54SSatish Kharat 	vnic_intr_free(&enic->admin_intr);
4813258931dSSatish Kharat 	vnic_cq_free(&enic->admin_cq[1]);
4823258931dSSatish Kharat 	vnic_cq_free(&enic->admin_cq[0]);
4833258931dSSatish Kharat 	vnic_rq_free(&enic->admin_rq);
4843258931dSSatish Kharat 	vnic_wq_free(&enic->admin_wq);
4853258931dSSatish Kharat }
4863258931dSSatish Kharat 
enic_admin_init_resources(struct enic * enic)4873258931dSSatish Kharat static void enic_admin_init_resources(struct enic *enic)
4883258931dSSatish Kharat {
489cb1dba54SSatish Kharat 	unsigned int intr_offset = enic->admin_intr_index;
490cb1dba54SSatish Kharat 
4913258931dSSatish Kharat 	vnic_wq_init(&enic->admin_wq,
4923258931dSSatish Kharat 		     0, 0, 0); /* cq_index, err_intr_enable, err_intr_offset */
4933258931dSSatish Kharat 	vnic_rq_init(&enic->admin_rq,
4943258931dSSatish Kharat 		     1, 0, 0); /* cq_index, err_intr_enable, err_intr_offset */
4953258931dSSatish Kharat 	vnic_cq_init(&enic->admin_cq[0],
4963258931dSSatish Kharat 		     VNIC_CQ_FC_DISABLE,
4973258931dSSatish Kharat 		     VNIC_CQ_COLOR_ENABLE,
4983258931dSSatish Kharat 		     0, 0, 1, /* cq_head, cq_tail, cq_tail_color */
499cb1dba54SSatish Kharat 		     VNIC_CQ_INTR_DISABLE, /* polled synchronously by mbox send */
5003258931dSSatish Kharat 		     VNIC_CQ_ENTRY_ENABLE,
5013258931dSSatish Kharat 		     VNIC_CQ_MSG_DISABLE,
502cb1dba54SSatish Kharat 		     intr_offset,
5033258931dSSatish Kharat 		     0 /* cq_message_addr */);
5043258931dSSatish Kharat 	vnic_cq_init(&enic->admin_cq[1],
5053258931dSSatish Kharat 		     VNIC_CQ_FC_DISABLE,
5063258931dSSatish Kharat 		     VNIC_CQ_COLOR_ENABLE,
5073258931dSSatish Kharat 		     0, 0, 1, /* cq_head, cq_tail, cq_tail_color */
508cb1dba54SSatish Kharat 		     VNIC_CQ_INTR_ENABLE,
5093258931dSSatish Kharat 		     VNIC_CQ_ENTRY_ENABLE,
5103258931dSSatish Kharat 		     VNIC_CQ_MSG_DISABLE,
511cb1dba54SSatish Kharat 		     intr_offset,
5123258931dSSatish Kharat 		     0 /* cq_message_addr */);
5131f0c856bSSatish Kharat 	/* coalescing_timer, coalescing_type, mask_on_assertion */
514cb1dba54SSatish Kharat 	vnic_intr_init(&enic->admin_intr,
5151f0c856bSSatish Kharat 		       0, 0, 1);
516cb1dba54SSatish Kharat }
517cb1dba54SSatish Kharat 
enic_admin_msg_drain(struct enic * enic)518cb1dba54SSatish Kharat static void enic_admin_msg_drain(struct enic *enic)
519cb1dba54SSatish Kharat {
520cb1dba54SSatish Kharat 	struct enic_admin_msg *msg, *tmp;
521cb1dba54SSatish Kharat 
522cb1dba54SSatish Kharat 	spin_lock_bh(&enic->admin_msg_lock);
523cb1dba54SSatish Kharat 	list_for_each_entry_safe(msg, tmp, &enic->admin_msg_list, list) {
524cb1dba54SSatish Kharat 		list_del(&msg->list);
525cb1dba54SSatish Kharat 		kfree(msg);
526cb1dba54SSatish Kharat 	}
527cb1dba54SSatish Kharat 	enic->admin_msg_count = 0;
528cb1dba54SSatish Kharat 	spin_unlock_bh(&enic->admin_msg_lock);
5293258931dSSatish Kharat }
5303258931dSSatish Kharat 
enic_admin_channel_open(struct enic * enic)5313258931dSSatish Kharat int enic_admin_channel_open(struct enic *enic)
5323258931dSSatish Kharat {
5333258931dSSatish Kharat 	int err;
5343258931dSSatish Kharat 
5353258931dSSatish Kharat 	if (!enic->has_admin_channel)
5363258931dSSatish Kharat 		return -ENODEV;
5373258931dSSatish Kharat 
5381f0c856bSSatish Kharat 	/* Keep MBOX sends disabled for the entire open sequence.  It is
5391f0c856bSSatish Kharat 	 * cleared only after every resource is allocated and enabled below,
5401f0c856bSSatish Kharat 	 * so any early error return here leaves sends disabled and a
5411f0c856bSSatish Kharat 	 * concurrent sender cannot touch a half-open or freed admin_wq.
5421f0c856bSSatish Kharat 	 */
5431f0c856bSSatish Kharat 	WRITE_ONCE(enic->mbox_send_disabled, true);
5441f0c856bSSatish Kharat 
5453258931dSSatish Kharat 	err = enic_admin_alloc_resources(enic);
5463258931dSSatish Kharat 	if (err) {
5473258931dSSatish Kharat 		netdev_err(enic->netdev,
5483258931dSSatish Kharat 			   "Failed to alloc admin channel resources: %d\n",
5493258931dSSatish Kharat 			   err);
5503258931dSSatish Kharat 		return err;
5513258931dSSatish Kharat 	}
5523258931dSSatish Kharat 
553cb1dba54SSatish Kharat 	spin_lock_init(&enic->admin_msg_lock);
554cb1dba54SSatish Kharat 	INIT_LIST_HEAD(&enic->admin_msg_list);
555cb1dba54SSatish Kharat 	INIT_WORK(&enic->admin_msg_work, enic_admin_msg_work_handler);
556cb1dba54SSatish Kharat 	INIT_DELAYED_WORK(&enic->admin_poll_work, enic_admin_poll_work_handler);
557cb1dba54SSatish Kharat 
558cb1dba54SSatish Kharat 	err = enic_admin_setup_intr(enic);
559cb1dba54SSatish Kharat 	if (err) {
560cb1dba54SSatish Kharat 		netdev_err(enic->netdev,
561cb1dba54SSatish Kharat 			   "Admin channel requires MSI-X, SR-IOV unavailable: %d\n",
562cb1dba54SSatish Kharat 			   err);
563cb1dba54SSatish Kharat 		goto free_resources;
564cb1dba54SSatish Kharat 	}
565cb1dba54SSatish Kharat 
5663258931dSSatish Kharat 	enic_admin_init_resources(enic);
5673258931dSSatish Kharat 
5683258931dSSatish Kharat 	vnic_wq_enable(&enic->admin_wq);
5693258931dSSatish Kharat 	vnic_rq_enable(&enic->admin_rq);
5703258931dSSatish Kharat 
571a0da4ea7SSatish Kharat 	err = enic_admin_rq_fill(enic, GFP_KERNEL);
572a0da4ea7SSatish Kharat 	if (err) {
573a0da4ea7SSatish Kharat 		netdev_err(enic->netdev,
574a0da4ea7SSatish Kharat 			   "Failed to fill admin RQ buffers: %d\n", err);
575a0da4ea7SSatish Kharat 		goto disable_queues;
576a0da4ea7SSatish Kharat 	}
577a0da4ea7SSatish Kharat 
5783258931dSSatish Kharat 	err = enic_admin_qp_type_set(enic, QP_ENABLE);
5793258931dSSatish Kharat 	if (err) {
5803258931dSSatish Kharat 		netdev_err(enic->netdev,
5813258931dSSatish Kharat 			   "Failed to set admin QP type: %d\n", err);
5823258931dSSatish Kharat 		goto disable_queues;
5833258931dSSatish Kharat 	}
5843258931dSSatish Kharat 
585cb1dba54SSatish Kharat 	vnic_intr_unmask(&enic->admin_intr);
586cb1dba54SSatish Kharat 
5871f0c856bSSatish Kharat 	/* Only now that the admin WQ/RQ/CQ and interrupt are fully allocated,
5881f0c856bSSatish Kharat 	 * programmed and enabled is it safe to allow MBOX sends.  Clearing this
5891f0c856bSSatish Kharat 	 * earlier opened a window where a concurrent sender (e.g. link-notify
5901f0c856bSSatish Kharat 	 * work scheduled by a post-reset link-up) could call enic_mbox_send_msg()
5911f0c856bSSatish Kharat 	 * against a not-yet-allocated admin_wq and crash.
5921f0c856bSSatish Kharat 	 */
5931f0c856bSSatish Kharat 	WRITE_ONCE(enic->mbox_send_disabled, false);
5941f0c856bSSatish Kharat 
595cb1dba54SSatish Kharat 	netdev_dbg(enic->netdev,
596cb1dba54SSatish Kharat 		   "admin channel open: intr=%u wq_avail=%u rq_avail=%u cq0_color=%u cq1_color=%u\n",
597cb1dba54SSatish Kharat 		   enic->admin_intr_index,
598cb1dba54SSatish Kharat 		   vnic_wq_desc_avail(&enic->admin_wq),
599cb1dba54SSatish Kharat 		   vnic_rq_desc_avail(&enic->admin_rq),
600cb1dba54SSatish Kharat 		   enic->admin_cq[0].last_color,
601cb1dba54SSatish Kharat 		   enic->admin_cq[1].last_color);
602cb1dba54SSatish Kharat 
6033258931dSSatish Kharat 	enic->admin_chan_up = true;
6043258931dSSatish Kharat 
6053258931dSSatish Kharat 	return 0;
6063258931dSSatish Kharat 
6073258931dSSatish Kharat disable_queues:
608cb1dba54SSatish Kharat 	enic_admin_teardown_intr(enic);
6093258931dSSatish Kharat 	enic_admin_qp_type_set(enic, QP_DISABLE);
6103258931dSSatish Kharat 	if (vnic_wq_disable(&enic->admin_wq))
6113258931dSSatish Kharat 		netdev_warn(enic->netdev, "Failed to disable admin WQ\n");
6123258931dSSatish Kharat 	if (vnic_rq_disable(&enic->admin_rq))
6133258931dSSatish Kharat 		netdev_warn(enic->netdev, "Failed to disable admin RQ\n");
614cb1dba54SSatish Kharat 	cancel_work_sync(&enic->admin_msg_work);
615cb1dba54SSatish Kharat 	enic_admin_msg_drain(enic);
616a0da4ea7SSatish Kharat 	enic_admin_rq_drain(enic);
617cb1dba54SSatish Kharat free_resources:
6183258931dSSatish Kharat 	enic_admin_free_resources(enic);
6193258931dSSatish Kharat 	return err;
6203258931dSSatish Kharat }
6213258931dSSatish Kharat 
enic_admin_channel_close(struct enic * enic)6223258931dSSatish Kharat void enic_admin_channel_close(struct enic *enic)
6233258931dSSatish Kharat {
6243258931dSSatish Kharat 	int err;
6253258931dSSatish Kharat 
6263258931dSSatish Kharat 	if (!enic->has_admin_channel)
6273258931dSSatish Kharat 		return;
6283258931dSSatish Kharat 
6293258931dSSatish Kharat 	/* Nothing to tear down if the channel was never (re)opened, e.g. a
6303258931dSSatish Kharat 	 * failed enic_admin_channel_open() in probe or in the reset path;
6313258931dSSatish Kharat 	 * otherwise the disable/clean calls below dereference freed resources.
6323258931dSSatish Kharat 	 */
6333258931dSSatish Kharat 	if (!enic->admin_chan_up)
6343258931dSSatish Kharat 		return;
6353258931dSSatish Kharat 
6361f0c856bSSatish Kharat 	WRITE_ONCE(enic->mbox_send_disabled, true);
6371f0c856bSSatish Kharat 
638cb1dba54SSatish Kharat 	netdev_dbg(enic->netdev, "admin channel close\n");
639cb1dba54SSatish Kharat 
640cb1dba54SSatish Kharat 	vnic_intr_mask(&enic->admin_intr);
641cb1dba54SSatish Kharat 	enic_admin_teardown_intr(enic);
642*4ff204ceSSatish Kharat 	cancel_work_sync(&enic->link_notify_work);
643cb1dba54SSatish Kharat 	cancel_work_sync(&enic->admin_msg_work);
644cb1dba54SSatish Kharat 	enic_admin_msg_drain(enic);
645cb1dba54SSatish Kharat 
6463258931dSSatish Kharat 	enic_admin_qp_type_set(enic, QP_DISABLE);
6473258931dSSatish Kharat 
6483258931dSSatish Kharat 	err = vnic_wq_disable(&enic->admin_wq);
6493258931dSSatish Kharat 	if (err)
6503258931dSSatish Kharat 		netdev_warn(enic->netdev,
6513258931dSSatish Kharat 			    "Failed to disable admin WQ: %d\n", err);
6523258931dSSatish Kharat 	err = vnic_rq_disable(&enic->admin_rq);
6533258931dSSatish Kharat 	if (err)
6543258931dSSatish Kharat 		netdev_warn(enic->netdev,
6553258931dSSatish Kharat 			    "Failed to disable admin RQ: %d\n", err);
6563258931dSSatish Kharat 
6573258931dSSatish Kharat 	vnic_wq_clean(&enic->admin_wq, enic_admin_wq_buf_clean);
658a0da4ea7SSatish Kharat 	enic_admin_rq_drain(enic);
6593258931dSSatish Kharat 	vnic_cq_clean(&enic->admin_cq[0]);
6603258931dSSatish Kharat 	vnic_cq_clean(&enic->admin_cq[1]);
661cb1dba54SSatish Kharat 	vnic_intr_clean(&enic->admin_intr);
662*4ff204ceSSatish Kharat 
663*4ff204ceSSatish Kharat 	enic->admin_rq_handler = NULL;
6643258931dSSatish Kharat 	enic_admin_free_resources(enic);
6653258931dSSatish Kharat 
6663258931dSSatish Kharat 	enic->admin_chan_up = false;
6673258931dSSatish Kharat }
668