xref: /linux/drivers/infiniband/hw/ionic/ionic_admin.c (revision e6d736bd08902ba53460df1b62ee4218bbd17d9b)
1f3bdbd42SAbhijit Gangurde // SPDX-License-Identifier: GPL-2.0
2f3bdbd42SAbhijit Gangurde /* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
3f3bdbd42SAbhijit Gangurde 
4f3bdbd42SAbhijit Gangurde #include <linux/interrupt.h>
5f3bdbd42SAbhijit Gangurde #include <linux/module.h>
6f3bdbd42SAbhijit Gangurde #include <linux/printk.h>
7f3bdbd42SAbhijit Gangurde 
8f3bdbd42SAbhijit Gangurde #include "ionic_fw.h"
9f3bdbd42SAbhijit Gangurde #include "ionic_ibdev.h"
10f3bdbd42SAbhijit Gangurde 
11f3bdbd42SAbhijit Gangurde #define IONIC_EQ_COUNT_MIN	4
12f3bdbd42SAbhijit Gangurde #define IONIC_AQ_COUNT_MIN	1
13f3bdbd42SAbhijit Gangurde 
14f3bdbd42SAbhijit Gangurde /* not a valid queue position or negative error status */
15f3bdbd42SAbhijit Gangurde #define IONIC_ADMIN_POSTED	0x10000
16f3bdbd42SAbhijit Gangurde 
17f3bdbd42SAbhijit Gangurde /* cpu can be held with irq disabled for COUNT * MS  (for create/destroy_ah) */
18f3bdbd42SAbhijit Gangurde #define IONIC_ADMIN_BUSY_RETRY_COUNT	2000
19f3bdbd42SAbhijit Gangurde #define IONIC_ADMIN_BUSY_RETRY_MS	1
20f3bdbd42SAbhijit Gangurde 
21f3bdbd42SAbhijit Gangurde /* admin queue will be considered failed if a command takes longer */
22f3bdbd42SAbhijit Gangurde #define IONIC_ADMIN_TIMEOUT	(HZ * 2)
23f3bdbd42SAbhijit Gangurde #define IONIC_ADMIN_WARN	(HZ / 8)
24f3bdbd42SAbhijit Gangurde 
25f3bdbd42SAbhijit Gangurde /* will poll for admin cq to tolerate and report from missed event */
26f3bdbd42SAbhijit Gangurde #define IONIC_ADMIN_DELAY	(HZ / 8)
27f3bdbd42SAbhijit Gangurde 
28f3bdbd42SAbhijit Gangurde /* work queue for polling the event queue and admin cq */
29f3bdbd42SAbhijit Gangurde struct workqueue_struct *ionic_evt_workq;
30f3bdbd42SAbhijit Gangurde 
31f3bdbd42SAbhijit Gangurde static void ionic_admin_timedout(struct ionic_aq *aq)
32f3bdbd42SAbhijit Gangurde {
33f3bdbd42SAbhijit Gangurde 	struct ionic_ibdev *dev = aq->dev;
34f3bdbd42SAbhijit Gangurde 	unsigned long irqflags;
35f3bdbd42SAbhijit Gangurde 	u16 pos;
36f3bdbd42SAbhijit Gangurde 
37f3bdbd42SAbhijit Gangurde 	spin_lock_irqsave(&aq->lock, irqflags);
38f3bdbd42SAbhijit Gangurde 	if (ionic_queue_empty(&aq->q))
39f3bdbd42SAbhijit Gangurde 		goto out;
40f3bdbd42SAbhijit Gangurde 
41f3bdbd42SAbhijit Gangurde 	/* Reset ALL adminq if any one times out */
42f3bdbd42SAbhijit Gangurde 	if (atomic_read(&aq->admin_state) < IONIC_ADMIN_KILLED)
43f3bdbd42SAbhijit Gangurde 		queue_work(ionic_evt_workq, &dev->reset_work);
44f3bdbd42SAbhijit Gangurde 
45f3bdbd42SAbhijit Gangurde 	ibdev_err(&dev->ibdev, "admin command timed out, aq %d after: %ums\n",
46f3bdbd42SAbhijit Gangurde 		  aq->aqid, (u32)jiffies_to_msecs(jiffies - aq->stamp));
47f3bdbd42SAbhijit Gangurde 
48f3bdbd42SAbhijit Gangurde 	pos = (aq->q.prod - 1) & aq->q.mask;
49f3bdbd42SAbhijit Gangurde 	if (pos == aq->q.cons)
50f3bdbd42SAbhijit Gangurde 		goto out;
51f3bdbd42SAbhijit Gangurde 
52f3bdbd42SAbhijit Gangurde 	ibdev_warn(&dev->ibdev, "admin pos %u (last posted)\n", pos);
53f3bdbd42SAbhijit Gangurde 	print_hex_dump(KERN_WARNING, "cmd ", DUMP_PREFIX_OFFSET, 16, 1,
54f3bdbd42SAbhijit Gangurde 		       ionic_queue_at(&aq->q, pos),
55f3bdbd42SAbhijit Gangurde 		       BIT(aq->q.stride_log2), true);
56f3bdbd42SAbhijit Gangurde 
57f3bdbd42SAbhijit Gangurde out:
58f3bdbd42SAbhijit Gangurde 	spin_unlock_irqrestore(&aq->lock, irqflags);
59f3bdbd42SAbhijit Gangurde }
60f3bdbd42SAbhijit Gangurde 
61f3bdbd42SAbhijit Gangurde static void ionic_admin_reset_dwork(struct ionic_ibdev *dev)
62f3bdbd42SAbhijit Gangurde {
63f3bdbd42SAbhijit Gangurde 	if (atomic_read(&dev->admin_state) == IONIC_ADMIN_KILLED)
64f3bdbd42SAbhijit Gangurde 		return;
65f3bdbd42SAbhijit Gangurde 
66f3bdbd42SAbhijit Gangurde 	queue_delayed_work(ionic_evt_workq, &dev->admin_dwork,
67f3bdbd42SAbhijit Gangurde 			   IONIC_ADMIN_DELAY);
68f3bdbd42SAbhijit Gangurde }
69f3bdbd42SAbhijit Gangurde 
70f3bdbd42SAbhijit Gangurde static void ionic_admin_reset_wdog(struct ionic_aq *aq)
71f3bdbd42SAbhijit Gangurde {
72f3bdbd42SAbhijit Gangurde 	if (atomic_read(&aq->admin_state) == IONIC_ADMIN_KILLED)
73f3bdbd42SAbhijit Gangurde 		return;
74f3bdbd42SAbhijit Gangurde 
75f3bdbd42SAbhijit Gangurde 	aq->stamp = jiffies;
76f3bdbd42SAbhijit Gangurde 	ionic_admin_reset_dwork(aq->dev);
77f3bdbd42SAbhijit Gangurde }
78f3bdbd42SAbhijit Gangurde 
79f3bdbd42SAbhijit Gangurde static bool ionic_admin_next_cqe(struct ionic_ibdev *dev, struct ionic_cq *cq,
80f3bdbd42SAbhijit Gangurde 				 struct ionic_v1_cqe **cqe)
81f3bdbd42SAbhijit Gangurde {
82f3bdbd42SAbhijit Gangurde 	struct ionic_v1_cqe *qcqe = ionic_queue_at_prod(&cq->q);
83f3bdbd42SAbhijit Gangurde 
84f3bdbd42SAbhijit Gangurde 	if (unlikely(cq->color != ionic_v1_cqe_color(qcqe)))
85f3bdbd42SAbhijit Gangurde 		return false;
86f3bdbd42SAbhijit Gangurde 
87f3bdbd42SAbhijit Gangurde 	/* Prevent out-of-order reads of the CQE */
88f3bdbd42SAbhijit Gangurde 	dma_rmb();
89f3bdbd42SAbhijit Gangurde 	*cqe = qcqe;
90f3bdbd42SAbhijit Gangurde 
91f3bdbd42SAbhijit Gangurde 	return true;
92f3bdbd42SAbhijit Gangurde }
93f3bdbd42SAbhijit Gangurde 
94f3bdbd42SAbhijit Gangurde static void ionic_admin_poll_locked(struct ionic_aq *aq)
95f3bdbd42SAbhijit Gangurde {
96f3bdbd42SAbhijit Gangurde 	struct ionic_cq *cq = &aq->vcq->cq[0];
97f3bdbd42SAbhijit Gangurde 	struct ionic_admin_wr *wr, *wr_next;
98f3bdbd42SAbhijit Gangurde 	struct ionic_ibdev *dev = aq->dev;
99f3bdbd42SAbhijit Gangurde 	u32 wr_strides, avlbl_strides;
100f3bdbd42SAbhijit Gangurde 	struct ionic_v1_cqe *cqe;
101f3bdbd42SAbhijit Gangurde 	u32 qtf, qid;
102f3bdbd42SAbhijit Gangurde 	u16 old_prod;
103f3bdbd42SAbhijit Gangurde 	u8 type;
104f3bdbd42SAbhijit Gangurde 
105f3bdbd42SAbhijit Gangurde 	lockdep_assert_held(&aq->lock);
106f3bdbd42SAbhijit Gangurde 
107f3bdbd42SAbhijit Gangurde 	if (atomic_read(&aq->admin_state) == IONIC_ADMIN_KILLED) {
108f3bdbd42SAbhijit Gangurde 		list_for_each_entry_safe(wr, wr_next, &aq->wr_prod, aq_ent) {
109f3bdbd42SAbhijit Gangurde 			INIT_LIST_HEAD(&wr->aq_ent);
110f3bdbd42SAbhijit Gangurde 			aq->q_wr[wr->status].wr = NULL;
111f3bdbd42SAbhijit Gangurde 			wr->status = atomic_read(&aq->admin_state);
112f3bdbd42SAbhijit Gangurde 			complete_all(&wr->work);
113f3bdbd42SAbhijit Gangurde 		}
114f3bdbd42SAbhijit Gangurde 		INIT_LIST_HEAD(&aq->wr_prod);
115f3bdbd42SAbhijit Gangurde 
116f3bdbd42SAbhijit Gangurde 		list_for_each_entry_safe(wr, wr_next, &aq->wr_post, aq_ent) {
117f3bdbd42SAbhijit Gangurde 			INIT_LIST_HEAD(&wr->aq_ent);
118f3bdbd42SAbhijit Gangurde 			wr->status = atomic_read(&aq->admin_state);
119f3bdbd42SAbhijit Gangurde 			complete_all(&wr->work);
120f3bdbd42SAbhijit Gangurde 		}
121f3bdbd42SAbhijit Gangurde 		INIT_LIST_HEAD(&aq->wr_post);
122f3bdbd42SAbhijit Gangurde 
123f3bdbd42SAbhijit Gangurde 		return;
124f3bdbd42SAbhijit Gangurde 	}
125f3bdbd42SAbhijit Gangurde 
126f3bdbd42SAbhijit Gangurde 	old_prod = cq->q.prod;
127f3bdbd42SAbhijit Gangurde 
128f3bdbd42SAbhijit Gangurde 	while (ionic_admin_next_cqe(dev, cq, &cqe)) {
129f3bdbd42SAbhijit Gangurde 		qtf = ionic_v1_cqe_qtf(cqe);
130f3bdbd42SAbhijit Gangurde 		qid = ionic_v1_cqe_qtf_qid(qtf);
131f3bdbd42SAbhijit Gangurde 		type = ionic_v1_cqe_qtf_type(qtf);
132f3bdbd42SAbhijit Gangurde 
133f3bdbd42SAbhijit Gangurde 		if (unlikely(type != IONIC_V1_CQE_TYPE_ADMIN)) {
134f3bdbd42SAbhijit Gangurde 			ibdev_warn_ratelimited(&dev->ibdev,
135f3bdbd42SAbhijit Gangurde 					       "bad cqe type %u\n", type);
136f3bdbd42SAbhijit Gangurde 			goto cq_next;
137f3bdbd42SAbhijit Gangurde 		}
138f3bdbd42SAbhijit Gangurde 
139f3bdbd42SAbhijit Gangurde 		if (unlikely(qid != aq->aqid)) {
140f3bdbd42SAbhijit Gangurde 			ibdev_warn_ratelimited(&dev->ibdev,
141f3bdbd42SAbhijit Gangurde 					       "bad cqe qid %u\n", qid);
142f3bdbd42SAbhijit Gangurde 			goto cq_next;
143f3bdbd42SAbhijit Gangurde 		}
144f3bdbd42SAbhijit Gangurde 
145f3bdbd42SAbhijit Gangurde 		if (unlikely(be16_to_cpu(cqe->admin.cmd_idx) != aq->q.cons)) {
146f3bdbd42SAbhijit Gangurde 			ibdev_warn_ratelimited(&dev->ibdev,
147f3bdbd42SAbhijit Gangurde 					       "bad idx %u cons %u qid %u\n",
148f3bdbd42SAbhijit Gangurde 					       be16_to_cpu(cqe->admin.cmd_idx),
149f3bdbd42SAbhijit Gangurde 					       aq->q.cons, qid);
150f3bdbd42SAbhijit Gangurde 			goto cq_next;
151f3bdbd42SAbhijit Gangurde 		}
152f3bdbd42SAbhijit Gangurde 
153f3bdbd42SAbhijit Gangurde 		if (unlikely(ionic_queue_empty(&aq->q))) {
154f3bdbd42SAbhijit Gangurde 			ibdev_warn_ratelimited(&dev->ibdev,
155f3bdbd42SAbhijit Gangurde 					       "bad cqe for empty adminq\n");
156f3bdbd42SAbhijit Gangurde 			goto cq_next;
157f3bdbd42SAbhijit Gangurde 		}
158f3bdbd42SAbhijit Gangurde 
159f3bdbd42SAbhijit Gangurde 		wr = aq->q_wr[aq->q.cons].wr;
160f3bdbd42SAbhijit Gangurde 		if (wr) {
161f3bdbd42SAbhijit Gangurde 			aq->q_wr[aq->q.cons].wr = NULL;
162f3bdbd42SAbhijit Gangurde 			list_del_init(&wr->aq_ent);
163f3bdbd42SAbhijit Gangurde 
164f3bdbd42SAbhijit Gangurde 			wr->cqe = *cqe;
165f3bdbd42SAbhijit Gangurde 			wr->status = atomic_read(&aq->admin_state);
166f3bdbd42SAbhijit Gangurde 			complete_all(&wr->work);
167f3bdbd42SAbhijit Gangurde 		}
168f3bdbd42SAbhijit Gangurde 
169f3bdbd42SAbhijit Gangurde 		ionic_queue_consume_entries(&aq->q,
170f3bdbd42SAbhijit Gangurde 					    aq->q_wr[aq->q.cons].wqe_strides);
171f3bdbd42SAbhijit Gangurde 
172f3bdbd42SAbhijit Gangurde cq_next:
173f3bdbd42SAbhijit Gangurde 		ionic_queue_produce(&cq->q);
174f3bdbd42SAbhijit Gangurde 		cq->color = ionic_color_wrap(cq->q.prod, cq->color);
175f3bdbd42SAbhijit Gangurde 	}
176f3bdbd42SAbhijit Gangurde 
177f3bdbd42SAbhijit Gangurde 	if (old_prod != cq->q.prod) {
178f3bdbd42SAbhijit Gangurde 		ionic_admin_reset_wdog(aq);
179f3bdbd42SAbhijit Gangurde 		cq->q.cons = cq->q.prod;
180f3bdbd42SAbhijit Gangurde 		ionic_dbell_ring(dev->lif_cfg.dbpage, dev->lif_cfg.cq_qtype,
181f3bdbd42SAbhijit Gangurde 				 ionic_queue_dbell_val(&cq->q));
182f3bdbd42SAbhijit Gangurde 		queue_work(ionic_evt_workq, &aq->work);
183f3bdbd42SAbhijit Gangurde 	} else if (!aq->armed) {
184f3bdbd42SAbhijit Gangurde 		aq->armed = true;
185f3bdbd42SAbhijit Gangurde 		cq->arm_any_prod = ionic_queue_next(&cq->q, cq->arm_any_prod);
186f3bdbd42SAbhijit Gangurde 		ionic_dbell_ring(dev->lif_cfg.dbpage, dev->lif_cfg.cq_qtype,
187f3bdbd42SAbhijit Gangurde 				 cq->q.dbell | IONIC_CQ_RING_ARM |
188f3bdbd42SAbhijit Gangurde 				 cq->arm_any_prod);
189f3bdbd42SAbhijit Gangurde 		queue_work(ionic_evt_workq, &aq->work);
190f3bdbd42SAbhijit Gangurde 	}
191f3bdbd42SAbhijit Gangurde 
192f3bdbd42SAbhijit Gangurde 	if (atomic_read(&aq->admin_state) != IONIC_ADMIN_ACTIVE)
193f3bdbd42SAbhijit Gangurde 		return;
194f3bdbd42SAbhijit Gangurde 
195f3bdbd42SAbhijit Gangurde 	old_prod = aq->q.prod;
196f3bdbd42SAbhijit Gangurde 
197f3bdbd42SAbhijit Gangurde 	if (ionic_queue_empty(&aq->q) && !list_empty(&aq->wr_post))
198f3bdbd42SAbhijit Gangurde 		ionic_admin_reset_wdog(aq);
199f3bdbd42SAbhijit Gangurde 
200f3bdbd42SAbhijit Gangurde 	if (list_empty(&aq->wr_post))
201f3bdbd42SAbhijit Gangurde 		return;
202f3bdbd42SAbhijit Gangurde 
203f3bdbd42SAbhijit Gangurde 	do {
204f3bdbd42SAbhijit Gangurde 		u8 *src;
205f3bdbd42SAbhijit Gangurde 		int i, src_len;
206f3bdbd42SAbhijit Gangurde 		size_t stride_len;
207f3bdbd42SAbhijit Gangurde 
208f3bdbd42SAbhijit Gangurde 		wr = list_first_entry(&aq->wr_post, struct ionic_admin_wr,
209f3bdbd42SAbhijit Gangurde 				      aq_ent);
210f3bdbd42SAbhijit Gangurde 		wr_strides = (le16_to_cpu(wr->wqe.len) + ADMIN_WQE_HDR_LEN +
211f3bdbd42SAbhijit Gangurde 			     (ADMIN_WQE_STRIDE - 1)) >> aq->q.stride_log2;
212f3bdbd42SAbhijit Gangurde 		avlbl_strides = ionic_queue_length_remaining(&aq->q);
213f3bdbd42SAbhijit Gangurde 
214f3bdbd42SAbhijit Gangurde 		if (wr_strides > avlbl_strides)
215f3bdbd42SAbhijit Gangurde 			break;
216f3bdbd42SAbhijit Gangurde 
217f3bdbd42SAbhijit Gangurde 		list_move(&wr->aq_ent, &aq->wr_prod);
218f3bdbd42SAbhijit Gangurde 		wr->status = aq->q.prod;
219f3bdbd42SAbhijit Gangurde 		aq->q_wr[aq->q.prod].wr = wr;
220f3bdbd42SAbhijit Gangurde 		aq->q_wr[aq->q.prod].wqe_strides = wr_strides;
221f3bdbd42SAbhijit Gangurde 
222f3bdbd42SAbhijit Gangurde 		src_len = le16_to_cpu(wr->wqe.len);
223f3bdbd42SAbhijit Gangurde 		src = (uint8_t *)&wr->wqe.cmd;
224f3bdbd42SAbhijit Gangurde 
225f3bdbd42SAbhijit Gangurde 		/* First stride */
226f3bdbd42SAbhijit Gangurde 		memcpy(ionic_queue_at_prod(&aq->q), &wr->wqe,
227f3bdbd42SAbhijit Gangurde 		       ADMIN_WQE_HDR_LEN);
228f3bdbd42SAbhijit Gangurde 		stride_len = ADMIN_WQE_STRIDE - ADMIN_WQE_HDR_LEN;
229f3bdbd42SAbhijit Gangurde 		if (stride_len > src_len)
230f3bdbd42SAbhijit Gangurde 			stride_len = src_len;
231f3bdbd42SAbhijit Gangurde 		memcpy(ionic_queue_at_prod(&aq->q) + ADMIN_WQE_HDR_LEN,
232f3bdbd42SAbhijit Gangurde 		       src, stride_len);
233f3bdbd42SAbhijit Gangurde 		ibdev_dbg(&dev->ibdev, "post admin prod %u (%u strides)\n",
234f3bdbd42SAbhijit Gangurde 			  aq->q.prod, wr_strides);
235f3bdbd42SAbhijit Gangurde 		print_hex_dump_debug("wqe ", DUMP_PREFIX_OFFSET, 16, 1,
236f3bdbd42SAbhijit Gangurde 				     ionic_queue_at_prod(&aq->q),
237f3bdbd42SAbhijit Gangurde 				     BIT(aq->q.stride_log2), true);
238f3bdbd42SAbhijit Gangurde 		ionic_queue_produce(&aq->q);
239f3bdbd42SAbhijit Gangurde 
240f3bdbd42SAbhijit Gangurde 		/* Remaining strides */
241f3bdbd42SAbhijit Gangurde 		for (i = stride_len; i < src_len; i += stride_len) {
242f3bdbd42SAbhijit Gangurde 			stride_len = ADMIN_WQE_STRIDE;
243f3bdbd42SAbhijit Gangurde 
244f3bdbd42SAbhijit Gangurde 			if (i + stride_len > src_len)
245f3bdbd42SAbhijit Gangurde 				stride_len = src_len - i;
246f3bdbd42SAbhijit Gangurde 
247f3bdbd42SAbhijit Gangurde 			memcpy(ionic_queue_at_prod(&aq->q), src + i,
248f3bdbd42SAbhijit Gangurde 			       stride_len);
249f3bdbd42SAbhijit Gangurde 			print_hex_dump_debug("wqe ", DUMP_PREFIX_OFFSET, 16, 1,
250f3bdbd42SAbhijit Gangurde 					     ionic_queue_at_prod(&aq->q),
251f3bdbd42SAbhijit Gangurde 					     BIT(aq->q.stride_log2), true);
252f3bdbd42SAbhijit Gangurde 			ionic_queue_produce(&aq->q);
253f3bdbd42SAbhijit Gangurde 		}
254f3bdbd42SAbhijit Gangurde 	} while (!list_empty(&aq->wr_post));
255f3bdbd42SAbhijit Gangurde 
256f3bdbd42SAbhijit Gangurde 	if (old_prod != aq->q.prod)
257f3bdbd42SAbhijit Gangurde 		ionic_dbell_ring(dev->lif_cfg.dbpage, dev->lif_cfg.aq_qtype,
258f3bdbd42SAbhijit Gangurde 				 ionic_queue_dbell_val(&aq->q));
259f3bdbd42SAbhijit Gangurde }
260f3bdbd42SAbhijit Gangurde 
261f3bdbd42SAbhijit Gangurde static void ionic_admin_dwork(struct work_struct *ws)
262f3bdbd42SAbhijit Gangurde {
263f3bdbd42SAbhijit Gangurde 	struct ionic_ibdev *dev =
264f3bdbd42SAbhijit Gangurde 		container_of(ws, struct ionic_ibdev, admin_dwork.work);
265f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq, *bad_aq = NULL;
266f3bdbd42SAbhijit Gangurde 	bool do_reschedule = false;
267f3bdbd42SAbhijit Gangurde 	unsigned long irqflags;
268f3bdbd42SAbhijit Gangurde 	bool do_reset = false;
269f3bdbd42SAbhijit Gangurde 	u16 pos;
270f3bdbd42SAbhijit Gangurde 	int i;
271f3bdbd42SAbhijit Gangurde 
272f3bdbd42SAbhijit Gangurde 	for (i = 0; i < dev->lif_cfg.aq_count; i++) {
273f3bdbd42SAbhijit Gangurde 		aq = dev->aq_vec[i];
274f3bdbd42SAbhijit Gangurde 
275f3bdbd42SAbhijit Gangurde 		spin_lock_irqsave(&aq->lock, irqflags);
276f3bdbd42SAbhijit Gangurde 
277f3bdbd42SAbhijit Gangurde 		if (ionic_queue_empty(&aq->q))
278f3bdbd42SAbhijit Gangurde 			goto next_aq;
279f3bdbd42SAbhijit Gangurde 
280f3bdbd42SAbhijit Gangurde 		/* Reschedule if any queue has outstanding work */
281f3bdbd42SAbhijit Gangurde 		do_reschedule = true;
282f3bdbd42SAbhijit Gangurde 
283f3bdbd42SAbhijit Gangurde 		if (time_is_after_eq_jiffies(aq->stamp + IONIC_ADMIN_WARN))
284f3bdbd42SAbhijit Gangurde 			/* Warning threshold not met, nothing to do */
285f3bdbd42SAbhijit Gangurde 			goto next_aq;
286f3bdbd42SAbhijit Gangurde 
287f3bdbd42SAbhijit Gangurde 		/* See if polling now makes some progress */
288f3bdbd42SAbhijit Gangurde 		pos = aq->q.cons;
289f3bdbd42SAbhijit Gangurde 		ionic_admin_poll_locked(aq);
290f3bdbd42SAbhijit Gangurde 		if (pos != aq->q.cons) {
291f3bdbd42SAbhijit Gangurde 			ibdev_dbg(&dev->ibdev,
292f3bdbd42SAbhijit Gangurde 				  "missed event for acq %d\n", aq->cqid);
293f3bdbd42SAbhijit Gangurde 			goto next_aq;
294f3bdbd42SAbhijit Gangurde 		}
295f3bdbd42SAbhijit Gangurde 
296f3bdbd42SAbhijit Gangurde 		if (time_is_after_eq_jiffies(aq->stamp +
297f3bdbd42SAbhijit Gangurde 					     IONIC_ADMIN_TIMEOUT)) {
298f3bdbd42SAbhijit Gangurde 			/* Timeout threshold not met */
299f3bdbd42SAbhijit Gangurde 			ibdev_dbg(&dev->ibdev, "no progress after %ums\n",
300f3bdbd42SAbhijit Gangurde 				  (u32)jiffies_to_msecs(jiffies - aq->stamp));
301f3bdbd42SAbhijit Gangurde 			goto next_aq;
302f3bdbd42SAbhijit Gangurde 		}
303f3bdbd42SAbhijit Gangurde 
304f3bdbd42SAbhijit Gangurde 		/* Queue timed out */
305f3bdbd42SAbhijit Gangurde 		bad_aq = aq;
306f3bdbd42SAbhijit Gangurde 		do_reset = true;
307f3bdbd42SAbhijit Gangurde next_aq:
308f3bdbd42SAbhijit Gangurde 		spin_unlock_irqrestore(&aq->lock, irqflags);
309f3bdbd42SAbhijit Gangurde 	}
310f3bdbd42SAbhijit Gangurde 
311f3bdbd42SAbhijit Gangurde 	if (do_reset)
312f3bdbd42SAbhijit Gangurde 		/* Reset RDMA lif on a timeout */
313f3bdbd42SAbhijit Gangurde 		ionic_admin_timedout(bad_aq);
314f3bdbd42SAbhijit Gangurde 	else if (do_reschedule)
315f3bdbd42SAbhijit Gangurde 		/* Try to poll again later */
316f3bdbd42SAbhijit Gangurde 		ionic_admin_reset_dwork(dev);
317f3bdbd42SAbhijit Gangurde }
318f3bdbd42SAbhijit Gangurde 
319f3bdbd42SAbhijit Gangurde static void ionic_admin_work(struct work_struct *ws)
320f3bdbd42SAbhijit Gangurde {
321f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq = container_of(ws, struct ionic_aq, work);
322f3bdbd42SAbhijit Gangurde 	unsigned long irqflags;
323f3bdbd42SAbhijit Gangurde 
324f3bdbd42SAbhijit Gangurde 	spin_lock_irqsave(&aq->lock, irqflags);
325f3bdbd42SAbhijit Gangurde 	ionic_admin_poll_locked(aq);
326f3bdbd42SAbhijit Gangurde 	spin_unlock_irqrestore(&aq->lock, irqflags);
327f3bdbd42SAbhijit Gangurde }
328f3bdbd42SAbhijit Gangurde 
329f3bdbd42SAbhijit Gangurde static void ionic_admin_post_aq(struct ionic_aq *aq, struct ionic_admin_wr *wr)
330f3bdbd42SAbhijit Gangurde {
331f3bdbd42SAbhijit Gangurde 	unsigned long irqflags;
332f3bdbd42SAbhijit Gangurde 	bool poll;
333f3bdbd42SAbhijit Gangurde 
334f3bdbd42SAbhijit Gangurde 	wr->status = IONIC_ADMIN_POSTED;
335f3bdbd42SAbhijit Gangurde 	wr->aq = aq;
336f3bdbd42SAbhijit Gangurde 
337f3bdbd42SAbhijit Gangurde 	spin_lock_irqsave(&aq->lock, irqflags);
338f3bdbd42SAbhijit Gangurde 	poll = list_empty(&aq->wr_post);
339f3bdbd42SAbhijit Gangurde 	list_add(&wr->aq_ent, &aq->wr_post);
340f3bdbd42SAbhijit Gangurde 	if (poll)
341f3bdbd42SAbhijit Gangurde 		ionic_admin_poll_locked(aq);
342f3bdbd42SAbhijit Gangurde 	spin_unlock_irqrestore(&aq->lock, irqflags);
343f3bdbd42SAbhijit Gangurde }
344f3bdbd42SAbhijit Gangurde 
345f3bdbd42SAbhijit Gangurde void ionic_admin_post(struct ionic_ibdev *dev, struct ionic_admin_wr *wr)
346f3bdbd42SAbhijit Gangurde {
347f3bdbd42SAbhijit Gangurde 	int aq_idx;
348f3bdbd42SAbhijit Gangurde 
349f3bdbd42SAbhijit Gangurde 	/* Use cpu id for the adminq selection */
350f3bdbd42SAbhijit Gangurde 	aq_idx = raw_smp_processor_id() % dev->lif_cfg.aq_count;
351f3bdbd42SAbhijit Gangurde 	ionic_admin_post_aq(dev->aq_vec[aq_idx], wr);
352f3bdbd42SAbhijit Gangurde }
353f3bdbd42SAbhijit Gangurde 
354f3bdbd42SAbhijit Gangurde static void ionic_admin_cancel(struct ionic_admin_wr *wr)
355f3bdbd42SAbhijit Gangurde {
356f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq = wr->aq;
357f3bdbd42SAbhijit Gangurde 	unsigned long irqflags;
358f3bdbd42SAbhijit Gangurde 
359f3bdbd42SAbhijit Gangurde 	spin_lock_irqsave(&aq->lock, irqflags);
360f3bdbd42SAbhijit Gangurde 
361f3bdbd42SAbhijit Gangurde 	if (!list_empty(&wr->aq_ent)) {
362f3bdbd42SAbhijit Gangurde 		list_del(&wr->aq_ent);
363f3bdbd42SAbhijit Gangurde 		if (wr->status != IONIC_ADMIN_POSTED)
364f3bdbd42SAbhijit Gangurde 			aq->q_wr[wr->status].wr = NULL;
365f3bdbd42SAbhijit Gangurde 	}
366f3bdbd42SAbhijit Gangurde 
367f3bdbd42SAbhijit Gangurde 	spin_unlock_irqrestore(&aq->lock, irqflags);
368f3bdbd42SAbhijit Gangurde }
369f3bdbd42SAbhijit Gangurde 
370f3bdbd42SAbhijit Gangurde static int ionic_admin_busy_wait(struct ionic_admin_wr *wr)
371f3bdbd42SAbhijit Gangurde {
372f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq = wr->aq;
373f3bdbd42SAbhijit Gangurde 	unsigned long irqflags;
374f3bdbd42SAbhijit Gangurde 	int try_i;
375f3bdbd42SAbhijit Gangurde 
376f3bdbd42SAbhijit Gangurde 	for (try_i = 0; try_i < IONIC_ADMIN_BUSY_RETRY_COUNT; ++try_i) {
377f3bdbd42SAbhijit Gangurde 		if (completion_done(&wr->work))
378f3bdbd42SAbhijit Gangurde 			return 0;
379f3bdbd42SAbhijit Gangurde 
380f3bdbd42SAbhijit Gangurde 		mdelay(IONIC_ADMIN_BUSY_RETRY_MS);
381f3bdbd42SAbhijit Gangurde 
382f3bdbd42SAbhijit Gangurde 		spin_lock_irqsave(&aq->lock, irqflags);
383f3bdbd42SAbhijit Gangurde 		ionic_admin_poll_locked(aq);
384f3bdbd42SAbhijit Gangurde 		spin_unlock_irqrestore(&aq->lock, irqflags);
385f3bdbd42SAbhijit Gangurde 	}
386f3bdbd42SAbhijit Gangurde 
387f3bdbd42SAbhijit Gangurde 	/*
388f3bdbd42SAbhijit Gangurde 	 * we timed out. Initiate RDMA LIF reset and indicate
389f3bdbd42SAbhijit Gangurde 	 * error to caller.
390f3bdbd42SAbhijit Gangurde 	 */
391f3bdbd42SAbhijit Gangurde 	ionic_admin_timedout(aq);
392f3bdbd42SAbhijit Gangurde 	return -ETIMEDOUT;
393f3bdbd42SAbhijit Gangurde }
394f3bdbd42SAbhijit Gangurde 
395f3bdbd42SAbhijit Gangurde int ionic_admin_wait(struct ionic_ibdev *dev, struct ionic_admin_wr *wr,
396f3bdbd42SAbhijit Gangurde 		     enum ionic_admin_flags flags)
397f3bdbd42SAbhijit Gangurde {
398f3bdbd42SAbhijit Gangurde 	int rc, timo;
399f3bdbd42SAbhijit Gangurde 
400f3bdbd42SAbhijit Gangurde 	if (flags & IONIC_ADMIN_F_BUSYWAIT) {
401f3bdbd42SAbhijit Gangurde 		/* Spin */
402f3bdbd42SAbhijit Gangurde 		rc = ionic_admin_busy_wait(wr);
403f3bdbd42SAbhijit Gangurde 	} else if (flags & IONIC_ADMIN_F_INTERRUPT) {
404f3bdbd42SAbhijit Gangurde 		/*
405f3bdbd42SAbhijit Gangurde 		 * Interruptible sleep, 1s timeout
406f3bdbd42SAbhijit Gangurde 		 * This is used for commands which are safe for the caller
407f3bdbd42SAbhijit Gangurde 		 * to clean up without killing and resetting the adminq.
408f3bdbd42SAbhijit Gangurde 		 */
409f3bdbd42SAbhijit Gangurde 		timo = wait_for_completion_interruptible_timeout(&wr->work,
410f3bdbd42SAbhijit Gangurde 								 HZ);
411f3bdbd42SAbhijit Gangurde 		if (timo > 0)
412f3bdbd42SAbhijit Gangurde 			rc = 0;
413f3bdbd42SAbhijit Gangurde 		else if (timo == 0)
414f3bdbd42SAbhijit Gangurde 			rc = -ETIMEDOUT;
415f3bdbd42SAbhijit Gangurde 		else
416f3bdbd42SAbhijit Gangurde 			rc = timo;
417f3bdbd42SAbhijit Gangurde 	} else {
418f3bdbd42SAbhijit Gangurde 		/*
419f3bdbd42SAbhijit Gangurde 		 * Uninterruptible sleep
420f3bdbd42SAbhijit Gangurde 		 * This is used for commands which are NOT safe for the
421f3bdbd42SAbhijit Gangurde 		 * caller to clean up. Cleanup must be handled by the
422f3bdbd42SAbhijit Gangurde 		 * adminq kill and reset process so that host memory is
423f3bdbd42SAbhijit Gangurde 		 * not corrupted by the device.
424f3bdbd42SAbhijit Gangurde 		 */
425f3bdbd42SAbhijit Gangurde 		wait_for_completion(&wr->work);
426f3bdbd42SAbhijit Gangurde 		rc = 0;
427f3bdbd42SAbhijit Gangurde 	}
428f3bdbd42SAbhijit Gangurde 
429f3bdbd42SAbhijit Gangurde 	if (rc) {
430f3bdbd42SAbhijit Gangurde 		ibdev_warn(&dev->ibdev, "wait status %d\n", rc);
431f3bdbd42SAbhijit Gangurde 		ionic_admin_cancel(wr);
432f3bdbd42SAbhijit Gangurde 	} else if (wr->status == IONIC_ADMIN_KILLED) {
433f3bdbd42SAbhijit Gangurde 		ibdev_dbg(&dev->ibdev, "admin killed\n");
434f3bdbd42SAbhijit Gangurde 
435f3bdbd42SAbhijit Gangurde 		/* No error if admin already killed during teardown */
436f3bdbd42SAbhijit Gangurde 		rc = (flags & IONIC_ADMIN_F_TEARDOWN) ? 0 : -ENODEV;
437f3bdbd42SAbhijit Gangurde 	} else if (ionic_v1_cqe_error(&wr->cqe)) {
438f3bdbd42SAbhijit Gangurde 		ibdev_warn(&dev->ibdev, "opcode %u error %u\n",
439f3bdbd42SAbhijit Gangurde 			   wr->wqe.op,
440f3bdbd42SAbhijit Gangurde 			   be32_to_cpu(wr->cqe.status_length));
441f3bdbd42SAbhijit Gangurde 		rc = -EINVAL;
442f3bdbd42SAbhijit Gangurde 	}
443f3bdbd42SAbhijit Gangurde 	return rc;
444f3bdbd42SAbhijit Gangurde }
445f3bdbd42SAbhijit Gangurde 
446f3bdbd42SAbhijit Gangurde static int ionic_rdma_devcmd(struct ionic_ibdev *dev,
447f3bdbd42SAbhijit Gangurde 			     struct ionic_admin_ctx *admin)
448f3bdbd42SAbhijit Gangurde {
449f3bdbd42SAbhijit Gangurde 	int rc;
450f3bdbd42SAbhijit Gangurde 
451f3bdbd42SAbhijit Gangurde 	rc = ionic_adminq_post_wait(dev->lif_cfg.lif, admin);
452f3bdbd42SAbhijit Gangurde 	if (rc)
453f3bdbd42SAbhijit Gangurde 		return rc;
454f3bdbd42SAbhijit Gangurde 
455f3bdbd42SAbhijit Gangurde 	return ionic_error_to_errno(admin->comp.comp.status);
456f3bdbd42SAbhijit Gangurde }
457f3bdbd42SAbhijit Gangurde 
458f3bdbd42SAbhijit Gangurde int ionic_rdma_reset_devcmd(struct ionic_ibdev *dev)
459f3bdbd42SAbhijit Gangurde {
460f3bdbd42SAbhijit Gangurde 	struct ionic_admin_ctx admin = {
461f3bdbd42SAbhijit Gangurde 		.work = COMPLETION_INITIALIZER_ONSTACK(admin.work),
462f3bdbd42SAbhijit Gangurde 		.cmd.rdma_reset = {
463f3bdbd42SAbhijit Gangurde 			.opcode = IONIC_CMD_RDMA_RESET_LIF,
464f3bdbd42SAbhijit Gangurde 			.lif_index = cpu_to_le16(dev->lif_cfg.lif_index),
465f3bdbd42SAbhijit Gangurde 		},
466f3bdbd42SAbhijit Gangurde 	};
467f3bdbd42SAbhijit Gangurde 
468f3bdbd42SAbhijit Gangurde 	return ionic_rdma_devcmd(dev, &admin);
469f3bdbd42SAbhijit Gangurde }
470f3bdbd42SAbhijit Gangurde 
471f3bdbd42SAbhijit Gangurde static int ionic_rdma_queue_devcmd(struct ionic_ibdev *dev,
472f3bdbd42SAbhijit Gangurde 				   struct ionic_queue *q,
473f3bdbd42SAbhijit Gangurde 				   u32 qid, u32 cid, u16 opcode)
474f3bdbd42SAbhijit Gangurde {
475f3bdbd42SAbhijit Gangurde 	struct ionic_admin_ctx admin = {
476f3bdbd42SAbhijit Gangurde 		.work = COMPLETION_INITIALIZER_ONSTACK(admin.work),
477f3bdbd42SAbhijit Gangurde 		.cmd.rdma_queue = {
478f3bdbd42SAbhijit Gangurde 			.opcode = opcode,
479f3bdbd42SAbhijit Gangurde 			.lif_index = cpu_to_le16(dev->lif_cfg.lif_index),
480f3bdbd42SAbhijit Gangurde 			.qid_ver = cpu_to_le32(qid),
481f3bdbd42SAbhijit Gangurde 			.cid = cpu_to_le32(cid),
482f3bdbd42SAbhijit Gangurde 			.dbid = cpu_to_le16(dev->lif_cfg.dbid),
483f3bdbd42SAbhijit Gangurde 			.depth_log2 = q->depth_log2,
484f3bdbd42SAbhijit Gangurde 			.stride_log2 = q->stride_log2,
485f3bdbd42SAbhijit Gangurde 			.dma_addr = cpu_to_le64(q->dma),
486f3bdbd42SAbhijit Gangurde 		},
487f3bdbd42SAbhijit Gangurde 	};
488f3bdbd42SAbhijit Gangurde 
489f3bdbd42SAbhijit Gangurde 	return ionic_rdma_devcmd(dev, &admin);
490f3bdbd42SAbhijit Gangurde }
491f3bdbd42SAbhijit Gangurde 
492f3bdbd42SAbhijit Gangurde static void ionic_rdma_admincq_comp(struct ib_cq *ibcq, void *cq_context)
493f3bdbd42SAbhijit Gangurde {
494f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq = cq_context;
495f3bdbd42SAbhijit Gangurde 	unsigned long irqflags;
496f3bdbd42SAbhijit Gangurde 
497f3bdbd42SAbhijit Gangurde 	spin_lock_irqsave(&aq->lock, irqflags);
498f3bdbd42SAbhijit Gangurde 	aq->armed = false;
499f3bdbd42SAbhijit Gangurde 	if (atomic_read(&aq->admin_state) < IONIC_ADMIN_KILLED)
500f3bdbd42SAbhijit Gangurde 		queue_work(ionic_evt_workq, &aq->work);
501f3bdbd42SAbhijit Gangurde 	spin_unlock_irqrestore(&aq->lock, irqflags);
502f3bdbd42SAbhijit Gangurde }
503f3bdbd42SAbhijit Gangurde 
504f3bdbd42SAbhijit Gangurde static void ionic_rdma_admincq_event(struct ib_event *event, void *cq_context)
505f3bdbd42SAbhijit Gangurde {
506f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq = cq_context;
507f3bdbd42SAbhijit Gangurde 
508f3bdbd42SAbhijit Gangurde 	ibdev_err(&aq->dev->ibdev, "admincq event %d\n", event->event);
509f3bdbd42SAbhijit Gangurde }
510f3bdbd42SAbhijit Gangurde 
511f3bdbd42SAbhijit Gangurde static struct ionic_vcq *ionic_create_rdma_admincq(struct ionic_ibdev *dev,
512f3bdbd42SAbhijit Gangurde 						   int comp_vector)
513f3bdbd42SAbhijit Gangurde {
514f3bdbd42SAbhijit Gangurde 	struct ib_cq_init_attr attr = {
515f3bdbd42SAbhijit Gangurde 		.cqe = IONIC_AQ_DEPTH,
516f3bdbd42SAbhijit Gangurde 		.comp_vector = comp_vector,
517f3bdbd42SAbhijit Gangurde 	};
518f3bdbd42SAbhijit Gangurde 	struct ionic_tbl_buf buf = {};
519f3bdbd42SAbhijit Gangurde 	struct ionic_vcq *vcq;
520f3bdbd42SAbhijit Gangurde 	struct ionic_cq *cq;
521f3bdbd42SAbhijit Gangurde 	int rc;
522f3bdbd42SAbhijit Gangurde 
523f3bdbd42SAbhijit Gangurde 	vcq = kzalloc(sizeof(*vcq), GFP_KERNEL);
524f3bdbd42SAbhijit Gangurde 	if (!vcq)
525f3bdbd42SAbhijit Gangurde 		return ERR_PTR(-ENOMEM);
526f3bdbd42SAbhijit Gangurde 
527f3bdbd42SAbhijit Gangurde 	vcq->ibcq.device = &dev->ibdev;
528f3bdbd42SAbhijit Gangurde 	vcq->ibcq.comp_handler = ionic_rdma_admincq_comp;
529f3bdbd42SAbhijit Gangurde 	vcq->ibcq.event_handler = ionic_rdma_admincq_event;
530f3bdbd42SAbhijit Gangurde 	atomic_set(&vcq->ibcq.usecnt, 0);
531f3bdbd42SAbhijit Gangurde 
532f3bdbd42SAbhijit Gangurde 	vcq->udma_mask = 1;
533f3bdbd42SAbhijit Gangurde 	cq = &vcq->cq[0];
534f3bdbd42SAbhijit Gangurde 
535f3bdbd42SAbhijit Gangurde 	rc = ionic_create_cq_common(vcq, &buf, &attr, NULL, NULL,
536f3bdbd42SAbhijit Gangurde 				    NULL, NULL, 0);
537f3bdbd42SAbhijit Gangurde 	if (rc)
538f3bdbd42SAbhijit Gangurde 		goto err_init;
539f3bdbd42SAbhijit Gangurde 
540f3bdbd42SAbhijit Gangurde 	rc = ionic_rdma_queue_devcmd(dev, &cq->q, cq->cqid, cq->eqid,
541f3bdbd42SAbhijit Gangurde 				     IONIC_CMD_RDMA_CREATE_CQ);
542f3bdbd42SAbhijit Gangurde 	if (rc)
543f3bdbd42SAbhijit Gangurde 		goto err_cmd;
544f3bdbd42SAbhijit Gangurde 
545f3bdbd42SAbhijit Gangurde 	return vcq;
546f3bdbd42SAbhijit Gangurde 
547f3bdbd42SAbhijit Gangurde err_cmd:
548f3bdbd42SAbhijit Gangurde 	ionic_destroy_cq_common(dev, cq);
549f3bdbd42SAbhijit Gangurde err_init:
550f3bdbd42SAbhijit Gangurde 	kfree(vcq);
551f3bdbd42SAbhijit Gangurde 
552f3bdbd42SAbhijit Gangurde 	return ERR_PTR(rc);
553f3bdbd42SAbhijit Gangurde }
554f3bdbd42SAbhijit Gangurde 
555f3bdbd42SAbhijit Gangurde static struct ionic_aq *__ionic_create_rdma_adminq(struct ionic_ibdev *dev,
556f3bdbd42SAbhijit Gangurde 						   u32 aqid, u32 cqid)
557f3bdbd42SAbhijit Gangurde {
558f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq;
559f3bdbd42SAbhijit Gangurde 	int rc;
560f3bdbd42SAbhijit Gangurde 
561f3bdbd42SAbhijit Gangurde 	aq = kzalloc(sizeof(*aq), GFP_KERNEL);
562f3bdbd42SAbhijit Gangurde 	if (!aq)
563f3bdbd42SAbhijit Gangurde 		return ERR_PTR(-ENOMEM);
564f3bdbd42SAbhijit Gangurde 
565f3bdbd42SAbhijit Gangurde 	atomic_set(&aq->admin_state, IONIC_ADMIN_KILLED);
566f3bdbd42SAbhijit Gangurde 	aq->dev = dev;
567f3bdbd42SAbhijit Gangurde 	aq->aqid = aqid;
568f3bdbd42SAbhijit Gangurde 	aq->cqid = cqid;
569f3bdbd42SAbhijit Gangurde 	spin_lock_init(&aq->lock);
570f3bdbd42SAbhijit Gangurde 
571f3bdbd42SAbhijit Gangurde 	rc = ionic_queue_init(&aq->q, dev->lif_cfg.hwdev, IONIC_EQ_DEPTH,
572f3bdbd42SAbhijit Gangurde 			      ADMIN_WQE_STRIDE);
573f3bdbd42SAbhijit Gangurde 	if (rc)
574f3bdbd42SAbhijit Gangurde 		goto err_q;
575f3bdbd42SAbhijit Gangurde 
576f3bdbd42SAbhijit Gangurde 	ionic_queue_dbell_init(&aq->q, aq->aqid);
577f3bdbd42SAbhijit Gangurde 
578f3bdbd42SAbhijit Gangurde 	aq->q_wr = kcalloc((u32)aq->q.mask + 1, sizeof(*aq->q_wr), GFP_KERNEL);
579f3bdbd42SAbhijit Gangurde 	if (!aq->q_wr) {
580f3bdbd42SAbhijit Gangurde 		rc = -ENOMEM;
581f3bdbd42SAbhijit Gangurde 		goto err_wr;
582f3bdbd42SAbhijit Gangurde 	}
583f3bdbd42SAbhijit Gangurde 
584f3bdbd42SAbhijit Gangurde 	INIT_LIST_HEAD(&aq->wr_prod);
585f3bdbd42SAbhijit Gangurde 	INIT_LIST_HEAD(&aq->wr_post);
586f3bdbd42SAbhijit Gangurde 
587f3bdbd42SAbhijit Gangurde 	INIT_WORK(&aq->work, ionic_admin_work);
588f3bdbd42SAbhijit Gangurde 	aq->armed = false;
589f3bdbd42SAbhijit Gangurde 
590f3bdbd42SAbhijit Gangurde 	return aq;
591f3bdbd42SAbhijit Gangurde 
592f3bdbd42SAbhijit Gangurde err_wr:
593f3bdbd42SAbhijit Gangurde 	ionic_queue_destroy(&aq->q, dev->lif_cfg.hwdev);
594f3bdbd42SAbhijit Gangurde err_q:
595f3bdbd42SAbhijit Gangurde 	kfree(aq);
596f3bdbd42SAbhijit Gangurde 
597f3bdbd42SAbhijit Gangurde 	return ERR_PTR(rc);
598f3bdbd42SAbhijit Gangurde }
599f3bdbd42SAbhijit Gangurde 
600f3bdbd42SAbhijit Gangurde static void __ionic_destroy_rdma_adminq(struct ionic_ibdev *dev,
601f3bdbd42SAbhijit Gangurde 					struct ionic_aq *aq)
602f3bdbd42SAbhijit Gangurde {
603*e6d736bdSAbhijit Gangurde 	kfree(aq->q_wr);
604f3bdbd42SAbhijit Gangurde 	ionic_queue_destroy(&aq->q, dev->lif_cfg.hwdev);
605f3bdbd42SAbhijit Gangurde 	kfree(aq);
606f3bdbd42SAbhijit Gangurde }
607f3bdbd42SAbhijit Gangurde 
608f3bdbd42SAbhijit Gangurde static struct ionic_aq *ionic_create_rdma_adminq(struct ionic_ibdev *dev,
609f3bdbd42SAbhijit Gangurde 						 u32 aqid, u32 cqid)
610f3bdbd42SAbhijit Gangurde {
611f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq;
612f3bdbd42SAbhijit Gangurde 	int rc;
613f3bdbd42SAbhijit Gangurde 
614f3bdbd42SAbhijit Gangurde 	aq = __ionic_create_rdma_adminq(dev, aqid, cqid);
615f3bdbd42SAbhijit Gangurde 	if (IS_ERR(aq))
616f3bdbd42SAbhijit Gangurde 		return aq;
617f3bdbd42SAbhijit Gangurde 
618f3bdbd42SAbhijit Gangurde 	rc = ionic_rdma_queue_devcmd(dev, &aq->q, aq->aqid, aq->cqid,
619f3bdbd42SAbhijit Gangurde 				     IONIC_CMD_RDMA_CREATE_ADMINQ);
620f3bdbd42SAbhijit Gangurde 	if (rc)
621f3bdbd42SAbhijit Gangurde 		goto err_cmd;
622f3bdbd42SAbhijit Gangurde 
623f3bdbd42SAbhijit Gangurde 	return aq;
624f3bdbd42SAbhijit Gangurde 
625f3bdbd42SAbhijit Gangurde err_cmd:
626f3bdbd42SAbhijit Gangurde 	__ionic_destroy_rdma_adminq(dev, aq);
627f3bdbd42SAbhijit Gangurde 
628f3bdbd42SAbhijit Gangurde 	return ERR_PTR(rc);
629f3bdbd42SAbhijit Gangurde }
630f3bdbd42SAbhijit Gangurde 
631e8521822SAbhijit Gangurde static void ionic_flush_qs(struct ionic_ibdev *dev)
632e8521822SAbhijit Gangurde {
633e8521822SAbhijit Gangurde 	struct ionic_qp *qp, *qp_tmp;
634e8521822SAbhijit Gangurde 	struct ionic_cq *cq, *cq_tmp;
635e8521822SAbhijit Gangurde 	LIST_HEAD(flush_list);
636e8521822SAbhijit Gangurde 	unsigned long index;
637e8521822SAbhijit Gangurde 
638e8521822SAbhijit Gangurde 	WARN_ON(!irqs_disabled());
639e8521822SAbhijit Gangurde 
640e8521822SAbhijit Gangurde 	/* Flush qp send and recv */
641e8521822SAbhijit Gangurde 	xa_lock(&dev->qp_tbl);
642e8521822SAbhijit Gangurde 	xa_for_each(&dev->qp_tbl, index, qp) {
643e8521822SAbhijit Gangurde 		kref_get(&qp->qp_kref);
644e8521822SAbhijit Gangurde 		list_add_tail(&qp->ibkill_flush_ent, &flush_list);
645e8521822SAbhijit Gangurde 	}
646e8521822SAbhijit Gangurde 	xa_unlock(&dev->qp_tbl);
647e8521822SAbhijit Gangurde 
648e8521822SAbhijit Gangurde 	list_for_each_entry_safe(qp, qp_tmp, &flush_list, ibkill_flush_ent) {
649e8521822SAbhijit Gangurde 		ionic_flush_qp(dev, qp);
650e8521822SAbhijit Gangurde 		kref_put(&qp->qp_kref, ionic_qp_complete);
651e8521822SAbhijit Gangurde 		list_del(&qp->ibkill_flush_ent);
652e8521822SAbhijit Gangurde 	}
653e8521822SAbhijit Gangurde 
654e8521822SAbhijit Gangurde 	/* Notify completions */
655e8521822SAbhijit Gangurde 	xa_lock(&dev->cq_tbl);
656e8521822SAbhijit Gangurde 	xa_for_each(&dev->cq_tbl, index, cq) {
657e8521822SAbhijit Gangurde 		kref_get(&cq->cq_kref);
658e8521822SAbhijit Gangurde 		list_add_tail(&cq->ibkill_flush_ent, &flush_list);
659e8521822SAbhijit Gangurde 	}
660e8521822SAbhijit Gangurde 	xa_unlock(&dev->cq_tbl);
661e8521822SAbhijit Gangurde 
662e8521822SAbhijit Gangurde 	list_for_each_entry_safe(cq, cq_tmp, &flush_list, ibkill_flush_ent) {
663e8521822SAbhijit Gangurde 		ionic_notify_flush_cq(cq);
664e8521822SAbhijit Gangurde 		kref_put(&cq->cq_kref, ionic_cq_complete);
665e8521822SAbhijit Gangurde 		list_del(&cq->ibkill_flush_ent);
666e8521822SAbhijit Gangurde 	}
667e8521822SAbhijit Gangurde }
668e8521822SAbhijit Gangurde 
669f3bdbd42SAbhijit Gangurde static void ionic_kill_ibdev(struct ionic_ibdev *dev, bool fatal_path)
670f3bdbd42SAbhijit Gangurde {
671f3bdbd42SAbhijit Gangurde 	unsigned long irqflags;
672f3bdbd42SAbhijit Gangurde 	bool do_flush = false;
673f3bdbd42SAbhijit Gangurde 	int i;
674f3bdbd42SAbhijit Gangurde 
675f3bdbd42SAbhijit Gangurde 	/* Mark AQs for drain and flush the QPs while irq is disabled */
676f3bdbd42SAbhijit Gangurde 	local_irq_save(irqflags);
677f3bdbd42SAbhijit Gangurde 
678f3bdbd42SAbhijit Gangurde 	/* Mark the admin queue, flushing at most once */
679f3bdbd42SAbhijit Gangurde 	for (i = 0; i < dev->lif_cfg.aq_count; i++) {
680f3bdbd42SAbhijit Gangurde 		struct ionic_aq *aq = dev->aq_vec[i];
681f3bdbd42SAbhijit Gangurde 
682f3bdbd42SAbhijit Gangurde 		spin_lock(&aq->lock);
683f3bdbd42SAbhijit Gangurde 		if (atomic_read(&aq->admin_state) != IONIC_ADMIN_KILLED) {
684f3bdbd42SAbhijit Gangurde 			atomic_set(&aq->admin_state, IONIC_ADMIN_KILLED);
685f3bdbd42SAbhijit Gangurde 			/* Flush incomplete admin commands */
686f3bdbd42SAbhijit Gangurde 			ionic_admin_poll_locked(aq);
687f3bdbd42SAbhijit Gangurde 			do_flush = true;
688f3bdbd42SAbhijit Gangurde 		}
689f3bdbd42SAbhijit Gangurde 		spin_unlock(&aq->lock);
690f3bdbd42SAbhijit Gangurde 	}
691f3bdbd42SAbhijit Gangurde 
692e8521822SAbhijit Gangurde 	if (do_flush)
693e8521822SAbhijit Gangurde 		ionic_flush_qs(dev);
694e8521822SAbhijit Gangurde 
695f3bdbd42SAbhijit Gangurde 	local_irq_restore(irqflags);
696f3bdbd42SAbhijit Gangurde 
697f3bdbd42SAbhijit Gangurde 	/* Post a fatal event if requested */
698f3bdbd42SAbhijit Gangurde 	if (fatal_path) {
699f3bdbd42SAbhijit Gangurde 		struct ib_event ev;
700f3bdbd42SAbhijit Gangurde 
701f3bdbd42SAbhijit Gangurde 		ev.device = &dev->ibdev;
702f3bdbd42SAbhijit Gangurde 		ev.element.port_num = 1;
703f3bdbd42SAbhijit Gangurde 		ev.event = IB_EVENT_DEVICE_FATAL;
704f3bdbd42SAbhijit Gangurde 
705f3bdbd42SAbhijit Gangurde 		ib_dispatch_event(&ev);
706f3bdbd42SAbhijit Gangurde 	}
707f3bdbd42SAbhijit Gangurde 
708f3bdbd42SAbhijit Gangurde 	atomic_set(&dev->admin_state, IONIC_ADMIN_KILLED);
709f3bdbd42SAbhijit Gangurde }
710f3bdbd42SAbhijit Gangurde 
711f3bdbd42SAbhijit Gangurde void ionic_kill_rdma_admin(struct ionic_ibdev *dev, bool fatal_path)
712f3bdbd42SAbhijit Gangurde {
713f3bdbd42SAbhijit Gangurde 	enum ionic_admin_state old_state;
714f3bdbd42SAbhijit Gangurde 	unsigned long irqflags = 0;
715f3bdbd42SAbhijit Gangurde 	int i, rc;
716f3bdbd42SAbhijit Gangurde 
717f3bdbd42SAbhijit Gangurde 	if (!dev->aq_vec)
718f3bdbd42SAbhijit Gangurde 		return;
719f3bdbd42SAbhijit Gangurde 
720f3bdbd42SAbhijit Gangurde 	/*
721f3bdbd42SAbhijit Gangurde 	 * Admin queues are transitioned from active to paused to killed state.
722f3bdbd42SAbhijit Gangurde 	 * When in paused state, no new commands are issued to the device,
723f3bdbd42SAbhijit Gangurde 	 * nor are any completed locally. After resetting the lif, it will be
724f3bdbd42SAbhijit Gangurde 	 * safe to resume the rdma admin queues in the killed state. Commands
725f3bdbd42SAbhijit Gangurde 	 * will not be issued to the device, but will complete locally with status
726f3bdbd42SAbhijit Gangurde 	 * IONIC_ADMIN_KILLED. Handling completion will ensure that creating or
727f3bdbd42SAbhijit Gangurde 	 * modifying resources fails, but destroying resources succeeds.
728f3bdbd42SAbhijit Gangurde 	 * If there was a failure resetting the lif using this strategy,
729f3bdbd42SAbhijit Gangurde 	 * then the state of the device is unknown.
730f3bdbd42SAbhijit Gangurde 	 */
731f3bdbd42SAbhijit Gangurde 	old_state = atomic_cmpxchg(&dev->admin_state, IONIC_ADMIN_ACTIVE,
732f3bdbd42SAbhijit Gangurde 				   IONIC_ADMIN_PAUSED);
733f3bdbd42SAbhijit Gangurde 	if (old_state != IONIC_ADMIN_ACTIVE)
734f3bdbd42SAbhijit Gangurde 		return;
735f3bdbd42SAbhijit Gangurde 
736f3bdbd42SAbhijit Gangurde 	/* Pause all the AQs */
737f3bdbd42SAbhijit Gangurde 	local_irq_save(irqflags);
738f3bdbd42SAbhijit Gangurde 	for (i = 0; i < dev->lif_cfg.aq_count; i++) {
739f3bdbd42SAbhijit Gangurde 		struct ionic_aq *aq = dev->aq_vec[i];
740f3bdbd42SAbhijit Gangurde 
741f3bdbd42SAbhijit Gangurde 		spin_lock(&aq->lock);
742f3bdbd42SAbhijit Gangurde 		/* pause rdma admin queues to reset lif */
743f3bdbd42SAbhijit Gangurde 		if (atomic_read(&aq->admin_state) == IONIC_ADMIN_ACTIVE)
744f3bdbd42SAbhijit Gangurde 			atomic_set(&aq->admin_state, IONIC_ADMIN_PAUSED);
745f3bdbd42SAbhijit Gangurde 		spin_unlock(&aq->lock);
746f3bdbd42SAbhijit Gangurde 	}
747f3bdbd42SAbhijit Gangurde 	local_irq_restore(irqflags);
748f3bdbd42SAbhijit Gangurde 
749f3bdbd42SAbhijit Gangurde 	rc = ionic_rdma_reset_devcmd(dev);
750f3bdbd42SAbhijit Gangurde 	if (unlikely(rc)) {
751f3bdbd42SAbhijit Gangurde 		ibdev_err(&dev->ibdev, "failed to reset rdma %d\n", rc);
752f3bdbd42SAbhijit Gangurde 		ionic_request_rdma_reset(dev->lif_cfg.lif);
753f3bdbd42SAbhijit Gangurde 	}
754f3bdbd42SAbhijit Gangurde 
755f3bdbd42SAbhijit Gangurde 	ionic_kill_ibdev(dev, fatal_path);
756f3bdbd42SAbhijit Gangurde }
757f3bdbd42SAbhijit Gangurde 
758f3bdbd42SAbhijit Gangurde static void ionic_reset_work(struct work_struct *ws)
759f3bdbd42SAbhijit Gangurde {
760f3bdbd42SAbhijit Gangurde 	struct ionic_ibdev *dev =
761f3bdbd42SAbhijit Gangurde 		container_of(ws, struct ionic_ibdev, reset_work);
762f3bdbd42SAbhijit Gangurde 
763f3bdbd42SAbhijit Gangurde 	ionic_kill_rdma_admin(dev, true);
764f3bdbd42SAbhijit Gangurde }
765f3bdbd42SAbhijit Gangurde 
766f3bdbd42SAbhijit Gangurde static bool ionic_next_eqe(struct ionic_eq *eq, struct ionic_v1_eqe *eqe)
767f3bdbd42SAbhijit Gangurde {
768f3bdbd42SAbhijit Gangurde 	struct ionic_v1_eqe *qeqe;
769f3bdbd42SAbhijit Gangurde 	bool color;
770f3bdbd42SAbhijit Gangurde 
771f3bdbd42SAbhijit Gangurde 	qeqe = ionic_queue_at_prod(&eq->q);
772f3bdbd42SAbhijit Gangurde 	color = ionic_v1_eqe_color(qeqe);
773f3bdbd42SAbhijit Gangurde 
774f3bdbd42SAbhijit Gangurde 	/* cons is color for eq */
775f3bdbd42SAbhijit Gangurde 	if (eq->q.cons != color)
776f3bdbd42SAbhijit Gangurde 		return false;
777f3bdbd42SAbhijit Gangurde 
778f3bdbd42SAbhijit Gangurde 	/* Prevent out-of-order reads of the EQE */
779f3bdbd42SAbhijit Gangurde 	dma_rmb();
780f3bdbd42SAbhijit Gangurde 
781f3bdbd42SAbhijit Gangurde 	ibdev_dbg(&eq->dev->ibdev, "poll eq prod %u\n", eq->q.prod);
782f3bdbd42SAbhijit Gangurde 	print_hex_dump_debug("eqe ", DUMP_PREFIX_OFFSET, 16, 1,
783f3bdbd42SAbhijit Gangurde 			     qeqe, BIT(eq->q.stride_log2), true);
784f3bdbd42SAbhijit Gangurde 	*eqe = *qeqe;
785f3bdbd42SAbhijit Gangurde 
786f3bdbd42SAbhijit Gangurde 	return true;
787f3bdbd42SAbhijit Gangurde }
788f3bdbd42SAbhijit Gangurde 
789f3bdbd42SAbhijit Gangurde static void ionic_cq_event(struct ionic_ibdev *dev, u32 cqid, u8 code)
790f3bdbd42SAbhijit Gangurde {
791f3bdbd42SAbhijit Gangurde 	unsigned long irqflags;
792f3bdbd42SAbhijit Gangurde 	struct ib_event ibev;
793f3bdbd42SAbhijit Gangurde 	struct ionic_cq *cq;
794f3bdbd42SAbhijit Gangurde 
795f3bdbd42SAbhijit Gangurde 	xa_lock_irqsave(&dev->cq_tbl, irqflags);
796f3bdbd42SAbhijit Gangurde 	cq = xa_load(&dev->cq_tbl, cqid);
797f3bdbd42SAbhijit Gangurde 	if (cq)
798f3bdbd42SAbhijit Gangurde 		kref_get(&cq->cq_kref);
799f3bdbd42SAbhijit Gangurde 	xa_unlock_irqrestore(&dev->cq_tbl, irqflags);
800f3bdbd42SAbhijit Gangurde 
801f3bdbd42SAbhijit Gangurde 	if (!cq) {
802f3bdbd42SAbhijit Gangurde 		ibdev_dbg(&dev->ibdev,
803f3bdbd42SAbhijit Gangurde 			  "missing cqid %#x code %u\n", cqid, code);
804f3bdbd42SAbhijit Gangurde 		return;
805f3bdbd42SAbhijit Gangurde 	}
806f3bdbd42SAbhijit Gangurde 
807f3bdbd42SAbhijit Gangurde 	switch (code) {
808f3bdbd42SAbhijit Gangurde 	case IONIC_V1_EQE_CQ_NOTIFY:
809f3bdbd42SAbhijit Gangurde 		if (cq->vcq->ibcq.comp_handler)
810f3bdbd42SAbhijit Gangurde 			cq->vcq->ibcq.comp_handler(&cq->vcq->ibcq,
811f3bdbd42SAbhijit Gangurde 						   cq->vcq->ibcq.cq_context);
812f3bdbd42SAbhijit Gangurde 		break;
813f3bdbd42SAbhijit Gangurde 
814f3bdbd42SAbhijit Gangurde 	case IONIC_V1_EQE_CQ_ERR:
815f3bdbd42SAbhijit Gangurde 		if (cq->vcq->ibcq.event_handler) {
816f3bdbd42SAbhijit Gangurde 			ibev.event = IB_EVENT_CQ_ERR;
817f3bdbd42SAbhijit Gangurde 			ibev.device = &dev->ibdev;
818f3bdbd42SAbhijit Gangurde 			ibev.element.cq = &cq->vcq->ibcq;
819f3bdbd42SAbhijit Gangurde 
820f3bdbd42SAbhijit Gangurde 			cq->vcq->ibcq.event_handler(&ibev,
821f3bdbd42SAbhijit Gangurde 						    cq->vcq->ibcq.cq_context);
822f3bdbd42SAbhijit Gangurde 		}
823f3bdbd42SAbhijit Gangurde 		break;
824f3bdbd42SAbhijit Gangurde 
825f3bdbd42SAbhijit Gangurde 	default:
826f3bdbd42SAbhijit Gangurde 		ibdev_dbg(&dev->ibdev,
827f3bdbd42SAbhijit Gangurde 			  "unrecognized cqid %#x code %u\n", cqid, code);
828f3bdbd42SAbhijit Gangurde 		break;
829f3bdbd42SAbhijit Gangurde 	}
830f3bdbd42SAbhijit Gangurde 
831f3bdbd42SAbhijit Gangurde 	kref_put(&cq->cq_kref, ionic_cq_complete);
832f3bdbd42SAbhijit Gangurde }
833f3bdbd42SAbhijit Gangurde 
834e8521822SAbhijit Gangurde static void ionic_qp_event(struct ionic_ibdev *dev, u32 qpid, u8 code)
835e8521822SAbhijit Gangurde {
836e8521822SAbhijit Gangurde 	unsigned long irqflags;
837e8521822SAbhijit Gangurde 	struct ib_event ibev;
838e8521822SAbhijit Gangurde 	struct ionic_qp *qp;
839e8521822SAbhijit Gangurde 
840e8521822SAbhijit Gangurde 	xa_lock_irqsave(&dev->qp_tbl, irqflags);
841e8521822SAbhijit Gangurde 	qp = xa_load(&dev->qp_tbl, qpid);
842e8521822SAbhijit Gangurde 	if (qp)
843e8521822SAbhijit Gangurde 		kref_get(&qp->qp_kref);
844e8521822SAbhijit Gangurde 	xa_unlock_irqrestore(&dev->qp_tbl, irqflags);
845e8521822SAbhijit Gangurde 
846e8521822SAbhijit Gangurde 	if (!qp) {
847e8521822SAbhijit Gangurde 		ibdev_dbg(&dev->ibdev,
848e8521822SAbhijit Gangurde 			  "missing qpid %#x code %u\n", qpid, code);
849e8521822SAbhijit Gangurde 		return;
850e8521822SAbhijit Gangurde 	}
851e8521822SAbhijit Gangurde 
852e8521822SAbhijit Gangurde 	ibev.device = &dev->ibdev;
853e8521822SAbhijit Gangurde 	ibev.element.qp = &qp->ibqp;
854e8521822SAbhijit Gangurde 
855e8521822SAbhijit Gangurde 	switch (code) {
856e8521822SAbhijit Gangurde 	case IONIC_V1_EQE_SQ_DRAIN:
857e8521822SAbhijit Gangurde 		ibev.event = IB_EVENT_SQ_DRAINED;
858e8521822SAbhijit Gangurde 		break;
859e8521822SAbhijit Gangurde 
860e8521822SAbhijit Gangurde 	case IONIC_V1_EQE_QP_COMM_EST:
861e8521822SAbhijit Gangurde 		ibev.event = IB_EVENT_COMM_EST;
862e8521822SAbhijit Gangurde 		break;
863e8521822SAbhijit Gangurde 
864e8521822SAbhijit Gangurde 	case IONIC_V1_EQE_QP_LAST_WQE:
865e8521822SAbhijit Gangurde 		ibev.event = IB_EVENT_QP_LAST_WQE_REACHED;
866e8521822SAbhijit Gangurde 		break;
867e8521822SAbhijit Gangurde 
868e8521822SAbhijit Gangurde 	case IONIC_V1_EQE_QP_ERR:
869e8521822SAbhijit Gangurde 		ibev.event = IB_EVENT_QP_FATAL;
870e8521822SAbhijit Gangurde 		break;
871e8521822SAbhijit Gangurde 
872e8521822SAbhijit Gangurde 	case IONIC_V1_EQE_QP_ERR_REQUEST:
873e8521822SAbhijit Gangurde 		ibev.event = IB_EVENT_QP_REQ_ERR;
874e8521822SAbhijit Gangurde 		break;
875e8521822SAbhijit Gangurde 
876e8521822SAbhijit Gangurde 	case IONIC_V1_EQE_QP_ERR_ACCESS:
877e8521822SAbhijit Gangurde 		ibev.event = IB_EVENT_QP_ACCESS_ERR;
878e8521822SAbhijit Gangurde 		break;
879e8521822SAbhijit Gangurde 
880e8521822SAbhijit Gangurde 	default:
881e8521822SAbhijit Gangurde 		ibdev_dbg(&dev->ibdev,
882e8521822SAbhijit Gangurde 			  "unrecognized qpid %#x code %u\n", qpid, code);
883e8521822SAbhijit Gangurde 		goto out;
884e8521822SAbhijit Gangurde 	}
885e8521822SAbhijit Gangurde 
886e8521822SAbhijit Gangurde 	if (qp->ibqp.event_handler)
887e8521822SAbhijit Gangurde 		qp->ibqp.event_handler(&ibev, qp->ibqp.qp_context);
888e8521822SAbhijit Gangurde 
889e8521822SAbhijit Gangurde out:
890e8521822SAbhijit Gangurde 	kref_put(&qp->qp_kref, ionic_qp_complete);
891e8521822SAbhijit Gangurde }
892e8521822SAbhijit Gangurde 
893f3bdbd42SAbhijit Gangurde static u16 ionic_poll_eq(struct ionic_eq *eq, u16 budget)
894f3bdbd42SAbhijit Gangurde {
895f3bdbd42SAbhijit Gangurde 	struct ionic_ibdev *dev = eq->dev;
896f3bdbd42SAbhijit Gangurde 	struct ionic_v1_eqe eqe;
897f3bdbd42SAbhijit Gangurde 	u16 npolled = 0;
898f3bdbd42SAbhijit Gangurde 	u8 type, code;
899f3bdbd42SAbhijit Gangurde 	u32 evt, qid;
900f3bdbd42SAbhijit Gangurde 
901f3bdbd42SAbhijit Gangurde 	while (npolled < budget) {
902f3bdbd42SAbhijit Gangurde 		if (!ionic_next_eqe(eq, &eqe))
903f3bdbd42SAbhijit Gangurde 			break;
904f3bdbd42SAbhijit Gangurde 
905f3bdbd42SAbhijit Gangurde 		ionic_queue_produce(&eq->q);
906f3bdbd42SAbhijit Gangurde 
907f3bdbd42SAbhijit Gangurde 		/* cons is color for eq */
908f3bdbd42SAbhijit Gangurde 		eq->q.cons = ionic_color_wrap(eq->q.prod, eq->q.cons);
909f3bdbd42SAbhijit Gangurde 
910f3bdbd42SAbhijit Gangurde 		++npolled;
911f3bdbd42SAbhijit Gangurde 
912f3bdbd42SAbhijit Gangurde 		evt = ionic_v1_eqe_evt(&eqe);
913f3bdbd42SAbhijit Gangurde 		type = ionic_v1_eqe_evt_type(evt);
914f3bdbd42SAbhijit Gangurde 		code = ionic_v1_eqe_evt_code(evt);
915f3bdbd42SAbhijit Gangurde 		qid = ionic_v1_eqe_evt_qid(evt);
916f3bdbd42SAbhijit Gangurde 
917f3bdbd42SAbhijit Gangurde 		switch (type) {
918f3bdbd42SAbhijit Gangurde 		case IONIC_V1_EQE_TYPE_CQ:
919f3bdbd42SAbhijit Gangurde 			ionic_cq_event(dev, qid, code);
920f3bdbd42SAbhijit Gangurde 			break;
921f3bdbd42SAbhijit Gangurde 
922e8521822SAbhijit Gangurde 		case IONIC_V1_EQE_TYPE_QP:
923e8521822SAbhijit Gangurde 			ionic_qp_event(dev, qid, code);
924e8521822SAbhijit Gangurde 			break;
925e8521822SAbhijit Gangurde 
926f3bdbd42SAbhijit Gangurde 		default:
927f3bdbd42SAbhijit Gangurde 			ibdev_dbg(&dev->ibdev,
928f3bdbd42SAbhijit Gangurde 				  "unknown event %#x type %u\n", evt, type);
929f3bdbd42SAbhijit Gangurde 		}
930f3bdbd42SAbhijit Gangurde 	}
931f3bdbd42SAbhijit Gangurde 
932f3bdbd42SAbhijit Gangurde 	return npolled;
933f3bdbd42SAbhijit Gangurde }
934f3bdbd42SAbhijit Gangurde 
935f3bdbd42SAbhijit Gangurde static void ionic_poll_eq_work(struct work_struct *work)
936f3bdbd42SAbhijit Gangurde {
937f3bdbd42SAbhijit Gangurde 	struct ionic_eq *eq = container_of(work, struct ionic_eq, work);
938f3bdbd42SAbhijit Gangurde 	u32 npolled;
939f3bdbd42SAbhijit Gangurde 
940f3bdbd42SAbhijit Gangurde 	if (unlikely(!eq->enable) || WARN_ON(eq->armed))
941f3bdbd42SAbhijit Gangurde 		return;
942f3bdbd42SAbhijit Gangurde 
943f3bdbd42SAbhijit Gangurde 	npolled = ionic_poll_eq(eq, IONIC_EQ_WORK_BUDGET);
944f3bdbd42SAbhijit Gangurde 	if (npolled == IONIC_EQ_WORK_BUDGET) {
945f3bdbd42SAbhijit Gangurde 		ionic_intr_credits(eq->dev->lif_cfg.intr_ctrl, eq->intr,
946f3bdbd42SAbhijit Gangurde 				   npolled, 0);
947f3bdbd42SAbhijit Gangurde 		queue_work(ionic_evt_workq, &eq->work);
948f3bdbd42SAbhijit Gangurde 	} else {
949ed9836c0SAbhijit Gangurde 		xchg(&eq->armed, 1);
950f3bdbd42SAbhijit Gangurde 		ionic_intr_credits(eq->dev->lif_cfg.intr_ctrl, eq->intr,
951f3bdbd42SAbhijit Gangurde 				   0, IONIC_INTR_CRED_UNMASK);
952f3bdbd42SAbhijit Gangurde 	}
953f3bdbd42SAbhijit Gangurde }
954f3bdbd42SAbhijit Gangurde 
955f3bdbd42SAbhijit Gangurde static irqreturn_t ionic_poll_eq_isr(int irq, void *eqptr)
956f3bdbd42SAbhijit Gangurde {
957f3bdbd42SAbhijit Gangurde 	struct ionic_eq *eq = eqptr;
958ed9836c0SAbhijit Gangurde 	int was_armed;
959f3bdbd42SAbhijit Gangurde 	u32 npolled;
960f3bdbd42SAbhijit Gangurde 
961ed9836c0SAbhijit Gangurde 	was_armed = xchg(&eq->armed, 0);
962f3bdbd42SAbhijit Gangurde 
963f3bdbd42SAbhijit Gangurde 	if (unlikely(!eq->enable) || !was_armed)
964f3bdbd42SAbhijit Gangurde 		return IRQ_HANDLED;
965f3bdbd42SAbhijit Gangurde 
966f3bdbd42SAbhijit Gangurde 	npolled = ionic_poll_eq(eq, IONIC_EQ_ISR_BUDGET);
967f3bdbd42SAbhijit Gangurde 	if (npolled == IONIC_EQ_ISR_BUDGET) {
968f3bdbd42SAbhijit Gangurde 		ionic_intr_credits(eq->dev->lif_cfg.intr_ctrl, eq->intr,
969f3bdbd42SAbhijit Gangurde 				   npolled, 0);
970f3bdbd42SAbhijit Gangurde 		queue_work(ionic_evt_workq, &eq->work);
971f3bdbd42SAbhijit Gangurde 	} else {
972ed9836c0SAbhijit Gangurde 		xchg(&eq->armed, 1);
973f3bdbd42SAbhijit Gangurde 		ionic_intr_credits(eq->dev->lif_cfg.intr_ctrl, eq->intr,
974f3bdbd42SAbhijit Gangurde 				   0, IONIC_INTR_CRED_UNMASK);
975f3bdbd42SAbhijit Gangurde 	}
976f3bdbd42SAbhijit Gangurde 
977f3bdbd42SAbhijit Gangurde 	return IRQ_HANDLED;
978f3bdbd42SAbhijit Gangurde }
979f3bdbd42SAbhijit Gangurde 
980f3bdbd42SAbhijit Gangurde static struct ionic_eq *ionic_create_eq(struct ionic_ibdev *dev, int eqid)
981f3bdbd42SAbhijit Gangurde {
982f3bdbd42SAbhijit Gangurde 	struct ionic_intr_info intr_obj = { };
983f3bdbd42SAbhijit Gangurde 	struct ionic_eq *eq;
984f3bdbd42SAbhijit Gangurde 	int rc;
985f3bdbd42SAbhijit Gangurde 
986f3bdbd42SAbhijit Gangurde 	eq = kzalloc(sizeof(*eq), GFP_KERNEL);
987f3bdbd42SAbhijit Gangurde 	if (!eq)
988f3bdbd42SAbhijit Gangurde 		return ERR_PTR(-ENOMEM);
989f3bdbd42SAbhijit Gangurde 
990f3bdbd42SAbhijit Gangurde 	eq->dev = dev;
991f3bdbd42SAbhijit Gangurde 
992f3bdbd42SAbhijit Gangurde 	rc = ionic_queue_init(&eq->q, dev->lif_cfg.hwdev, IONIC_EQ_DEPTH,
993f3bdbd42SAbhijit Gangurde 			      sizeof(struct ionic_v1_eqe));
994f3bdbd42SAbhijit Gangurde 	if (rc)
995f3bdbd42SAbhijit Gangurde 		goto err_q;
996f3bdbd42SAbhijit Gangurde 
997f3bdbd42SAbhijit Gangurde 	eq->eqid = eqid;
998f3bdbd42SAbhijit Gangurde 
999f3bdbd42SAbhijit Gangurde 	eq->armed = true;
1000f3bdbd42SAbhijit Gangurde 	eq->enable = false;
1001f3bdbd42SAbhijit Gangurde 	INIT_WORK(&eq->work, ionic_poll_eq_work);
1002f3bdbd42SAbhijit Gangurde 
1003f3bdbd42SAbhijit Gangurde 	rc = ionic_intr_alloc(dev->lif_cfg.lif, &intr_obj);
1004f3bdbd42SAbhijit Gangurde 	if (rc < 0)
1005f3bdbd42SAbhijit Gangurde 		goto err_intr;
1006f3bdbd42SAbhijit Gangurde 
1007f3bdbd42SAbhijit Gangurde 	eq->irq = intr_obj.vector;
1008f3bdbd42SAbhijit Gangurde 	eq->intr = intr_obj.index;
1009f3bdbd42SAbhijit Gangurde 
1010f3bdbd42SAbhijit Gangurde 	ionic_queue_dbell_init(&eq->q, eq->eqid);
1011f3bdbd42SAbhijit Gangurde 
1012f3bdbd42SAbhijit Gangurde 	/* cons is color for eq */
1013f3bdbd42SAbhijit Gangurde 	eq->q.cons = true;
1014f3bdbd42SAbhijit Gangurde 
1015f3bdbd42SAbhijit Gangurde 	snprintf(eq->name, sizeof(eq->name), "%s-%d-%d-eq",
1016f3bdbd42SAbhijit Gangurde 		 "ionr", dev->lif_cfg.lif_index, eq->eqid);
1017f3bdbd42SAbhijit Gangurde 
1018f3bdbd42SAbhijit Gangurde 	ionic_intr_mask(dev->lif_cfg.intr_ctrl, eq->intr, IONIC_INTR_MASK_SET);
1019f3bdbd42SAbhijit Gangurde 	ionic_intr_mask_assert(dev->lif_cfg.intr_ctrl, eq->intr, IONIC_INTR_MASK_SET);
1020f3bdbd42SAbhijit Gangurde 	ionic_intr_coal_init(dev->lif_cfg.intr_ctrl, eq->intr, 0);
1021f3bdbd42SAbhijit Gangurde 	ionic_intr_clean(dev->lif_cfg.intr_ctrl, eq->intr);
1022f3bdbd42SAbhijit Gangurde 
1023f3bdbd42SAbhijit Gangurde 	eq->enable = true;
1024f3bdbd42SAbhijit Gangurde 
1025f3bdbd42SAbhijit Gangurde 	rc = request_irq(eq->irq, ionic_poll_eq_isr, 0, eq->name, eq);
1026f3bdbd42SAbhijit Gangurde 	if (rc)
1027f3bdbd42SAbhijit Gangurde 		goto err_irq;
1028f3bdbd42SAbhijit Gangurde 
1029f3bdbd42SAbhijit Gangurde 	rc = ionic_rdma_queue_devcmd(dev, &eq->q, eq->eqid, eq->intr,
1030f3bdbd42SAbhijit Gangurde 				     IONIC_CMD_RDMA_CREATE_EQ);
1031f3bdbd42SAbhijit Gangurde 	if (rc)
1032f3bdbd42SAbhijit Gangurde 		goto err_cmd;
1033f3bdbd42SAbhijit Gangurde 
1034f3bdbd42SAbhijit Gangurde 	ionic_intr_mask(dev->lif_cfg.intr_ctrl, eq->intr, IONIC_INTR_MASK_CLEAR);
1035f3bdbd42SAbhijit Gangurde 
1036f3bdbd42SAbhijit Gangurde 	return eq;
1037f3bdbd42SAbhijit Gangurde 
1038f3bdbd42SAbhijit Gangurde err_cmd:
1039f3bdbd42SAbhijit Gangurde 	eq->enable = false;
1040f3bdbd42SAbhijit Gangurde 	free_irq(eq->irq, eq);
1041f3bdbd42SAbhijit Gangurde 	flush_work(&eq->work);
1042f3bdbd42SAbhijit Gangurde err_irq:
1043f3bdbd42SAbhijit Gangurde 	ionic_intr_free(dev->lif_cfg.lif, eq->intr);
1044f3bdbd42SAbhijit Gangurde err_intr:
1045f3bdbd42SAbhijit Gangurde 	ionic_queue_destroy(&eq->q, dev->lif_cfg.hwdev);
1046f3bdbd42SAbhijit Gangurde err_q:
1047f3bdbd42SAbhijit Gangurde 	kfree(eq);
1048f3bdbd42SAbhijit Gangurde 
1049f3bdbd42SAbhijit Gangurde 	return ERR_PTR(rc);
1050f3bdbd42SAbhijit Gangurde }
1051f3bdbd42SAbhijit Gangurde 
1052f3bdbd42SAbhijit Gangurde static void ionic_destroy_eq(struct ionic_eq *eq)
1053f3bdbd42SAbhijit Gangurde {
1054f3bdbd42SAbhijit Gangurde 	struct ionic_ibdev *dev = eq->dev;
1055f3bdbd42SAbhijit Gangurde 
1056f3bdbd42SAbhijit Gangurde 	eq->enable = false;
1057f3bdbd42SAbhijit Gangurde 	free_irq(eq->irq, eq);
1058f3bdbd42SAbhijit Gangurde 	flush_work(&eq->work);
1059f3bdbd42SAbhijit Gangurde 
1060f3bdbd42SAbhijit Gangurde 	ionic_intr_free(dev->lif_cfg.lif, eq->intr);
1061f3bdbd42SAbhijit Gangurde 	ionic_queue_destroy(&eq->q, dev->lif_cfg.hwdev);
1062f3bdbd42SAbhijit Gangurde 	kfree(eq);
1063f3bdbd42SAbhijit Gangurde }
1064f3bdbd42SAbhijit Gangurde 
1065f3bdbd42SAbhijit Gangurde int ionic_create_rdma_admin(struct ionic_ibdev *dev)
1066f3bdbd42SAbhijit Gangurde {
1067f3bdbd42SAbhijit Gangurde 	int eq_i = 0, aq_i = 0, rc = 0;
1068f3bdbd42SAbhijit Gangurde 	struct ionic_vcq *vcq;
1069f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq;
1070f3bdbd42SAbhijit Gangurde 	struct ionic_eq *eq;
1071f3bdbd42SAbhijit Gangurde 
1072f3bdbd42SAbhijit Gangurde 	dev->eq_vec = NULL;
1073f3bdbd42SAbhijit Gangurde 	dev->aq_vec = NULL;
1074f3bdbd42SAbhijit Gangurde 
1075f3bdbd42SAbhijit Gangurde 	INIT_WORK(&dev->reset_work, ionic_reset_work);
1076f3bdbd42SAbhijit Gangurde 	INIT_DELAYED_WORK(&dev->admin_dwork, ionic_admin_dwork);
1077f3bdbd42SAbhijit Gangurde 	atomic_set(&dev->admin_state, IONIC_ADMIN_KILLED);
1078f3bdbd42SAbhijit Gangurde 
1079f3bdbd42SAbhijit Gangurde 	if (dev->lif_cfg.aq_count > IONIC_AQ_COUNT) {
1080f3bdbd42SAbhijit Gangurde 		ibdev_dbg(&dev->ibdev, "limiting adminq count to %d\n",
1081f3bdbd42SAbhijit Gangurde 			  IONIC_AQ_COUNT);
1082f3bdbd42SAbhijit Gangurde 		dev->lif_cfg.aq_count = IONIC_AQ_COUNT;
1083f3bdbd42SAbhijit Gangurde 	}
1084f3bdbd42SAbhijit Gangurde 
1085f3bdbd42SAbhijit Gangurde 	if (dev->lif_cfg.eq_count > IONIC_EQ_COUNT) {
1086f3bdbd42SAbhijit Gangurde 		dev_dbg(&dev->ibdev.dev, "limiting eventq count to %d\n",
1087f3bdbd42SAbhijit Gangurde 			IONIC_EQ_COUNT);
1088f3bdbd42SAbhijit Gangurde 		dev->lif_cfg.eq_count = IONIC_EQ_COUNT;
1089f3bdbd42SAbhijit Gangurde 	}
1090f3bdbd42SAbhijit Gangurde 
1091f3bdbd42SAbhijit Gangurde 	/* need at least two eq and one aq */
1092f3bdbd42SAbhijit Gangurde 	if (dev->lif_cfg.eq_count < IONIC_EQ_COUNT_MIN ||
1093f3bdbd42SAbhijit Gangurde 	    dev->lif_cfg.aq_count < IONIC_AQ_COUNT_MIN) {
1094f3bdbd42SAbhijit Gangurde 		rc = -EINVAL;
1095f3bdbd42SAbhijit Gangurde 		goto out;
1096f3bdbd42SAbhijit Gangurde 	}
1097f3bdbd42SAbhijit Gangurde 
1098f3bdbd42SAbhijit Gangurde 	dev->eq_vec = kmalloc_array(dev->lif_cfg.eq_count, sizeof(*dev->eq_vec),
1099f3bdbd42SAbhijit Gangurde 				    GFP_KERNEL);
1100f3bdbd42SAbhijit Gangurde 	if (!dev->eq_vec) {
1101f3bdbd42SAbhijit Gangurde 		rc = -ENOMEM;
1102f3bdbd42SAbhijit Gangurde 		goto out;
1103f3bdbd42SAbhijit Gangurde 	}
1104f3bdbd42SAbhijit Gangurde 
1105f3bdbd42SAbhijit Gangurde 	for (eq_i = 0; eq_i < dev->lif_cfg.eq_count; ++eq_i) {
1106f3bdbd42SAbhijit Gangurde 		eq = ionic_create_eq(dev, eq_i + dev->lif_cfg.eq_base);
1107f3bdbd42SAbhijit Gangurde 		if (IS_ERR(eq)) {
1108f3bdbd42SAbhijit Gangurde 			rc = PTR_ERR(eq);
1109f3bdbd42SAbhijit Gangurde 
1110f3bdbd42SAbhijit Gangurde 			if (eq_i < IONIC_EQ_COUNT_MIN) {
1111f3bdbd42SAbhijit Gangurde 				ibdev_err(&dev->ibdev,
11124b6b6233SLeon Romanovsky 					  "fail create eq %pe\n", eq);
1113f3bdbd42SAbhijit Gangurde 				goto out;
1114f3bdbd42SAbhijit Gangurde 			}
1115f3bdbd42SAbhijit Gangurde 
1116f3bdbd42SAbhijit Gangurde 			/* ok, just fewer eq than device supports */
11174b6b6233SLeon Romanovsky 			ibdev_dbg(&dev->ibdev, "eq count %d want %d rc %pe\n",
11184b6b6233SLeon Romanovsky 				  eq_i, dev->lif_cfg.eq_count, eq);
1119f3bdbd42SAbhijit Gangurde 
1120f3bdbd42SAbhijit Gangurde 			rc = 0;
1121f3bdbd42SAbhijit Gangurde 			break;
1122f3bdbd42SAbhijit Gangurde 		}
1123f3bdbd42SAbhijit Gangurde 
1124f3bdbd42SAbhijit Gangurde 		dev->eq_vec[eq_i] = eq;
1125f3bdbd42SAbhijit Gangurde 	}
1126f3bdbd42SAbhijit Gangurde 
1127f3bdbd42SAbhijit Gangurde 	dev->lif_cfg.eq_count = eq_i;
1128f3bdbd42SAbhijit Gangurde 
1129f3bdbd42SAbhijit Gangurde 	dev->aq_vec = kmalloc_array(dev->lif_cfg.aq_count, sizeof(*dev->aq_vec),
1130f3bdbd42SAbhijit Gangurde 				    GFP_KERNEL);
1131f3bdbd42SAbhijit Gangurde 	if (!dev->aq_vec) {
1132f3bdbd42SAbhijit Gangurde 		rc = -ENOMEM;
1133f3bdbd42SAbhijit Gangurde 		goto out;
1134f3bdbd42SAbhijit Gangurde 	}
1135f3bdbd42SAbhijit Gangurde 
1136f3bdbd42SAbhijit Gangurde 	/* Create one CQ per AQ */
1137f3bdbd42SAbhijit Gangurde 	for (aq_i = 0; aq_i < dev->lif_cfg.aq_count; ++aq_i) {
1138f3bdbd42SAbhijit Gangurde 		vcq = ionic_create_rdma_admincq(dev, aq_i % eq_i);
1139f3bdbd42SAbhijit Gangurde 		if (IS_ERR(vcq)) {
1140f3bdbd42SAbhijit Gangurde 			rc = PTR_ERR(vcq);
1141f3bdbd42SAbhijit Gangurde 
1142f3bdbd42SAbhijit Gangurde 			if (!aq_i) {
1143f3bdbd42SAbhijit Gangurde 				ibdev_err(&dev->ibdev,
11444b6b6233SLeon Romanovsky 					  "failed to create acq %pe\n", vcq);
1145f3bdbd42SAbhijit Gangurde 				goto out;
1146f3bdbd42SAbhijit Gangurde 			}
1147f3bdbd42SAbhijit Gangurde 
1148f3bdbd42SAbhijit Gangurde 			/* ok, just fewer adminq than device supports */
11494b6b6233SLeon Romanovsky 			ibdev_dbg(&dev->ibdev, "acq count %d want %d rc %pe\n",
11504b6b6233SLeon Romanovsky 				  aq_i, dev->lif_cfg.aq_count, vcq);
1151f3bdbd42SAbhijit Gangurde 			break;
1152f3bdbd42SAbhijit Gangurde 		}
1153f3bdbd42SAbhijit Gangurde 
1154f3bdbd42SAbhijit Gangurde 		aq = ionic_create_rdma_adminq(dev, aq_i + dev->lif_cfg.aq_base,
1155f3bdbd42SAbhijit Gangurde 					      vcq->cq[0].cqid);
1156f3bdbd42SAbhijit Gangurde 		if (IS_ERR(aq)) {
1157f3bdbd42SAbhijit Gangurde 			/* Clean up the dangling CQ */
1158f3bdbd42SAbhijit Gangurde 			ionic_destroy_cq_common(dev, &vcq->cq[0]);
1159f3bdbd42SAbhijit Gangurde 			kfree(vcq);
1160f3bdbd42SAbhijit Gangurde 
1161f3bdbd42SAbhijit Gangurde 			rc = PTR_ERR(aq);
1162f3bdbd42SAbhijit Gangurde 
1163f3bdbd42SAbhijit Gangurde 			if (!aq_i) {
1164f3bdbd42SAbhijit Gangurde 				ibdev_err(&dev->ibdev,
11654b6b6233SLeon Romanovsky 					  "failed to create aq %pe\n", aq);
1166f3bdbd42SAbhijit Gangurde 				goto out;
1167f3bdbd42SAbhijit Gangurde 			}
1168f3bdbd42SAbhijit Gangurde 
1169f3bdbd42SAbhijit Gangurde 			/* ok, just fewer adminq than device supports */
11704b6b6233SLeon Romanovsky 			ibdev_dbg(&dev->ibdev, "aq count %d want %d rc %pe\n",
11714b6b6233SLeon Romanovsky 				  aq_i, dev->lif_cfg.aq_count, aq);
1172f3bdbd42SAbhijit Gangurde 			break;
1173f3bdbd42SAbhijit Gangurde 		}
1174f3bdbd42SAbhijit Gangurde 
1175f3bdbd42SAbhijit Gangurde 		vcq->ibcq.cq_context = aq;
1176f3bdbd42SAbhijit Gangurde 		aq->vcq = vcq;
1177f3bdbd42SAbhijit Gangurde 
1178f3bdbd42SAbhijit Gangurde 		atomic_set(&aq->admin_state, IONIC_ADMIN_ACTIVE);
1179f3bdbd42SAbhijit Gangurde 		dev->aq_vec[aq_i] = aq;
1180f3bdbd42SAbhijit Gangurde 	}
1181f3bdbd42SAbhijit Gangurde 
1182f3bdbd42SAbhijit Gangurde 	atomic_set(&dev->admin_state, IONIC_ADMIN_ACTIVE);
1183f3bdbd42SAbhijit Gangurde out:
1184f3bdbd42SAbhijit Gangurde 	dev->lif_cfg.eq_count = eq_i;
1185f3bdbd42SAbhijit Gangurde 	dev->lif_cfg.aq_count = aq_i;
1186f3bdbd42SAbhijit Gangurde 
1187f3bdbd42SAbhijit Gangurde 	return rc;
1188f3bdbd42SAbhijit Gangurde }
1189f3bdbd42SAbhijit Gangurde 
1190f3bdbd42SAbhijit Gangurde void ionic_destroy_rdma_admin(struct ionic_ibdev *dev)
1191f3bdbd42SAbhijit Gangurde {
1192f3bdbd42SAbhijit Gangurde 	struct ionic_vcq *vcq;
1193f3bdbd42SAbhijit Gangurde 	struct ionic_aq *aq;
1194f3bdbd42SAbhijit Gangurde 	struct ionic_eq *eq;
1195f3bdbd42SAbhijit Gangurde 
1196f3bdbd42SAbhijit Gangurde 	/*
1197f3bdbd42SAbhijit Gangurde 	 * Killing the admin before destroy makes sure all admin and
1198f3bdbd42SAbhijit Gangurde 	 * completions are flushed. admin_state = IONIC_ADMIN_KILLED
1199f3bdbd42SAbhijit Gangurde 	 * stops queueing up further works.
1200f3bdbd42SAbhijit Gangurde 	 */
1201f3bdbd42SAbhijit Gangurde 	cancel_delayed_work_sync(&dev->admin_dwork);
1202f3bdbd42SAbhijit Gangurde 	cancel_work_sync(&dev->reset_work);
1203f3bdbd42SAbhijit Gangurde 
1204f3bdbd42SAbhijit Gangurde 	if (dev->aq_vec) {
1205f3bdbd42SAbhijit Gangurde 		while (dev->lif_cfg.aq_count > 0) {
1206f3bdbd42SAbhijit Gangurde 			aq = dev->aq_vec[--dev->lif_cfg.aq_count];
1207f3bdbd42SAbhijit Gangurde 			vcq = aq->vcq;
1208f3bdbd42SAbhijit Gangurde 
1209f3bdbd42SAbhijit Gangurde 			cancel_work_sync(&aq->work);
1210f3bdbd42SAbhijit Gangurde 
1211f3bdbd42SAbhijit Gangurde 			__ionic_destroy_rdma_adminq(dev, aq);
1212f3bdbd42SAbhijit Gangurde 			if (vcq) {
1213f3bdbd42SAbhijit Gangurde 				ionic_destroy_cq_common(dev, &vcq->cq[0]);
1214f3bdbd42SAbhijit Gangurde 				kfree(vcq);
1215f3bdbd42SAbhijit Gangurde 			}
1216f3bdbd42SAbhijit Gangurde 		}
1217f3bdbd42SAbhijit Gangurde 
1218f3bdbd42SAbhijit Gangurde 		kfree(dev->aq_vec);
1219f3bdbd42SAbhijit Gangurde 	}
1220f3bdbd42SAbhijit Gangurde 
1221f3bdbd42SAbhijit Gangurde 	if (dev->eq_vec) {
1222f3bdbd42SAbhijit Gangurde 		while (dev->lif_cfg.eq_count > 0) {
1223f3bdbd42SAbhijit Gangurde 			eq = dev->eq_vec[--dev->lif_cfg.eq_count];
1224f3bdbd42SAbhijit Gangurde 			ionic_destroy_eq(eq);
1225f3bdbd42SAbhijit Gangurde 		}
1226f3bdbd42SAbhijit Gangurde 
1227f3bdbd42SAbhijit Gangurde 		kfree(dev->eq_vec);
1228f3bdbd42SAbhijit Gangurde 	}
1229f3bdbd42SAbhijit Gangurde }
1230