ib_cq.c revision 331769
1/* 2 * Copyright (c) 2017 Mellanox Technologies Ltd. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33#include <linux/module.h> 34#include <linux/err.h> 35#include <linux/slab.h> 36 37#include <rdma/ib_verbs.h> 38 39#define IB_CQ_POLL_MAX 16 40/* maximum number of completions per poll loop */ 41#define IB_CQ_POLL_BUDGET 65536 42#define IB_CQ_POLL_FLAGS (IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS) 43 44static void 45ib_cq_poll_work(struct work_struct *work) 46{ 47 struct ib_wc ib_wc[IB_CQ_POLL_MAX]; 48 struct ib_cq *cq = container_of(work, struct ib_cq, work); 49 int total = 0; 50 int i; 51 int n; 52 53 while (1) { 54 n = ib_poll_cq(cq, IB_CQ_POLL_MAX, ib_wc); 55 for (i = 0; i < n; i++) { 56 struct ib_wc *wc = ib_wc + i; 57 58 if (wc->wr_cqe != NULL) 59 wc->wr_cqe->done(cq, wc); 60 } 61 62 if (n != IB_CQ_POLL_MAX) { 63 if (ib_req_notify_cq(cq, IB_CQ_POLL_FLAGS) > 0) 64 break; 65 else 66 return; 67 } 68 total += n; 69 if (total >= IB_CQ_POLL_BUDGET) 70 break; 71 } 72 73 /* give other work structs a chance */ 74 queue_work(ib_comp_wq, &cq->work); 75} 76 77static void 78ib_cq_completion_workqueue(struct ib_cq *cq, void *private) 79{ 80 queue_work(ib_comp_wq, &cq->work); 81} 82 83struct ib_cq * 84ib_alloc_cq(struct ib_device *dev, void *private, 85 int nr_cqe, int comp_vector, enum ib_poll_context poll_ctx) 86{ 87 struct ib_cq_init_attr cq_attr = { 88 .cqe = nr_cqe, 89 .comp_vector = comp_vector, 90 }; 91 struct ib_cq *cq; 92 93 /* 94 * Check for invalid parameters early on to avoid 95 * extra error handling code: 96 */ 97 switch (poll_ctx) { 98 case IB_POLL_DIRECT: 99 case IB_POLL_SOFTIRQ: 100 case IB_POLL_WORKQUEUE: 101 break; 102 default: 103 return (ERR_PTR(-EINVAL)); 104 } 105 106 cq = dev->create_cq(dev, &cq_attr, NULL, NULL); 107 if (IS_ERR(cq)) 108 return (cq); 109 110 cq->device = dev; 111 cq->uobject = NULL; 112 cq->event_handler = NULL; 113 cq->cq_context = private; 114 cq->poll_ctx = poll_ctx; 115 atomic_set(&cq->usecnt, 0); 116 117 switch (poll_ctx) { 118 case IB_POLL_DIRECT: 119 cq->comp_handler = NULL; /* no hardware completions */ 120 break; 121 case IB_POLL_SOFTIRQ: 122 case IB_POLL_WORKQUEUE: 123 cq->comp_handler = ib_cq_completion_workqueue; 124 INIT_WORK(&cq->work, ib_cq_poll_work); 125 ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); 126 break; 127 default: 128 break; 129 } 130 return (cq); 131} 132EXPORT_SYMBOL(ib_alloc_cq); 133 134void 135ib_free_cq(struct ib_cq *cq) 136{ 137 138 if (WARN_ON_ONCE(atomic_read(&cq->usecnt) != 0)) 139 return; 140 141 switch (cq->poll_ctx) { 142 case IB_POLL_DIRECT: 143 break; 144 case IB_POLL_SOFTIRQ: 145 case IB_POLL_WORKQUEUE: 146 flush_work(&cq->work); 147 break; 148 default: 149 break; 150 } 151 152 (void)cq->device->destroy_cq(cq); 153} 154EXPORT_SYMBOL(ib_free_cq); 155