1 /* 2 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 3 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 4 * 5 * This software is available to you under a choice of one of two 6 * licenses. You may choose to be licensed under the terms of the GNU 7 * General Public License (GPL) Version 2, available from the file 8 * COPYING in the main directory of this source tree, or the 9 * OpenIB.org BSD license below: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * - Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 #include "rxe.h" 35 #include "rxe_loc.h" 36 #include "rxe_queue.h" 37 38 int rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq, 39 int cqe, int comp_vector, struct ib_udata *udata) 40 { 41 int count; 42 43 if (cqe <= 0) { 44 pr_warn("cqe(%d) <= 0\n", cqe); 45 goto err1; 46 } 47 48 if (cqe > rxe->attr.max_cqe) { 49 pr_warn("cqe(%d) > max_cqe(%d)\n", 50 cqe, rxe->attr.max_cqe); 51 goto err1; 52 } 53 54 if (cq) { 55 count = queue_count(cq->queue); 56 if (cqe < count) { 57 pr_warn("cqe(%d) < current # elements in queue (%d)", 58 cqe, count); 59 goto err1; 60 } 61 } 62 63 return 0; 64 65 err1: 66 return -EINVAL; 67 } 68 69 static void rxe_send_complete(unsigned long data) 70 { 71 struct rxe_cq *cq = (struct rxe_cq *)data; 72 73 cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); 74 } 75 76 int rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, 77 int comp_vector, struct ib_ucontext *context, 78 struct ib_udata *udata) 79 { 80 int err; 81 82 cq->queue = rxe_queue_init(rxe, &cqe, 83 sizeof(struct rxe_cqe)); 84 if (!cq->queue) { 85 pr_warn("unable to create cq\n"); 86 return -ENOMEM; 87 } 88 89 err = do_mmap_info(rxe, udata, false, context, cq->queue->buf, 90 cq->queue->buf_size, &cq->queue->ip); 91 if (err) { 92 kvfree(cq->queue->buf); 93 kfree(cq->queue); 94 return err; 95 } 96 97 if (udata) 98 cq->is_user = 1; 99 100 tasklet_init(&cq->comp_task, rxe_send_complete, (unsigned long)cq); 101 102 spin_lock_init(&cq->cq_lock); 103 cq->ibcq.cqe = cqe; 104 return 0; 105 } 106 107 int rxe_cq_resize_queue(struct rxe_cq *cq, int cqe, struct ib_udata *udata) 108 { 109 int err; 110 111 err = rxe_queue_resize(cq->queue, (unsigned int *)&cqe, 112 sizeof(struct rxe_cqe), 113 cq->queue->ip ? cq->queue->ip->context : NULL, 114 udata, NULL, &cq->cq_lock); 115 if (!err) 116 cq->ibcq.cqe = cqe; 117 118 return err; 119 } 120 121 int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited) 122 { 123 struct ib_event ev; 124 unsigned long flags; 125 126 spin_lock_irqsave(&cq->cq_lock, flags); 127 128 if (unlikely(queue_full(cq->queue))) { 129 spin_unlock_irqrestore(&cq->cq_lock, flags); 130 if (cq->ibcq.event_handler) { 131 ev.device = cq->ibcq.device; 132 ev.element.cq = &cq->ibcq; 133 ev.event = IB_EVENT_CQ_ERR; 134 cq->ibcq.event_handler(&ev, cq->ibcq.cq_context); 135 } 136 137 return -EBUSY; 138 } 139 140 memcpy(producer_addr(cq->queue), cqe, sizeof(*cqe)); 141 142 /* make sure all changes to the CQ are written before we update the 143 * producer pointer 144 */ 145 smp_wmb(); 146 147 advance_producer(cq->queue); 148 spin_unlock_irqrestore(&cq->cq_lock, flags); 149 150 if ((cq->notify == IB_CQ_NEXT_COMP) || 151 (cq->notify == IB_CQ_SOLICITED && solicited)) { 152 cq->notify = 0; 153 tasklet_schedule(&cq->comp_task); 154 } 155 156 return 0; 157 } 158 159 void rxe_cq_cleanup(void *arg) 160 { 161 struct rxe_cq *cq = arg; 162 163 if (cq->queue) 164 rxe_queue_cleanup(cq->queue); 165 } 166