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