162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/vmalloc.h> 762306a36Sopenharmony_ci#include "rxe.h" 862306a36Sopenharmony_ci#include "rxe_loc.h" 962306a36Sopenharmony_ci#include "rxe_queue.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciint rxe_cq_chk_attr(struct rxe_dev *rxe, struct rxe_cq *cq, 1262306a36Sopenharmony_ci int cqe, int comp_vector) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci int count; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci if (cqe <= 0) { 1762306a36Sopenharmony_ci rxe_dbg_dev(rxe, "cqe(%d) <= 0\n", cqe); 1862306a36Sopenharmony_ci goto err1; 1962306a36Sopenharmony_ci } 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci if (cqe > rxe->attr.max_cqe) { 2262306a36Sopenharmony_ci rxe_dbg_dev(rxe, "cqe(%d) > max_cqe(%d)\n", 2362306a36Sopenharmony_ci cqe, rxe->attr.max_cqe); 2462306a36Sopenharmony_ci goto err1; 2562306a36Sopenharmony_ci } 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci if (cq) { 2862306a36Sopenharmony_ci count = queue_count(cq->queue, QUEUE_TYPE_TO_CLIENT); 2962306a36Sopenharmony_ci if (cqe < count) { 3062306a36Sopenharmony_ci rxe_dbg_cq(cq, "cqe(%d) < current # elements in queue (%d)", 3162306a36Sopenharmony_ci cqe, count); 3262306a36Sopenharmony_ci goto err1; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return 0; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cierr1: 3962306a36Sopenharmony_ci return -EINVAL; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciint rxe_cq_from_init(struct rxe_dev *rxe, struct rxe_cq *cq, int cqe, 4362306a36Sopenharmony_ci int comp_vector, struct ib_udata *udata, 4462306a36Sopenharmony_ci struct rxe_create_cq_resp __user *uresp) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci int err; 4762306a36Sopenharmony_ci enum queue_type type; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci type = QUEUE_TYPE_TO_CLIENT; 5062306a36Sopenharmony_ci cq->queue = rxe_queue_init(rxe, &cqe, 5162306a36Sopenharmony_ci sizeof(struct rxe_cqe), type); 5262306a36Sopenharmony_ci if (!cq->queue) { 5362306a36Sopenharmony_ci rxe_dbg_dev(rxe, "unable to create cq\n"); 5462306a36Sopenharmony_ci return -ENOMEM; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci err = do_mmap_info(rxe, uresp ? &uresp->mi : NULL, udata, 5862306a36Sopenharmony_ci cq->queue->buf, cq->queue->buf_size, &cq->queue->ip); 5962306a36Sopenharmony_ci if (err) { 6062306a36Sopenharmony_ci vfree(cq->queue->buf); 6162306a36Sopenharmony_ci kfree(cq->queue); 6262306a36Sopenharmony_ci return err; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci cq->is_user = uresp; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci spin_lock_init(&cq->cq_lock); 6862306a36Sopenharmony_ci cq->ibcq.cqe = cqe; 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciint rxe_cq_resize_queue(struct rxe_cq *cq, int cqe, 7362306a36Sopenharmony_ci struct rxe_resize_cq_resp __user *uresp, 7462306a36Sopenharmony_ci struct ib_udata *udata) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci int err; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci err = rxe_queue_resize(cq->queue, (unsigned int *)&cqe, 7962306a36Sopenharmony_ci sizeof(struct rxe_cqe), udata, 8062306a36Sopenharmony_ci uresp ? &uresp->mi : NULL, NULL, &cq->cq_lock); 8162306a36Sopenharmony_ci if (!err) 8262306a36Sopenharmony_ci cq->ibcq.cqe = cqe; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return err; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* caller holds reference to cq */ 8862306a36Sopenharmony_ciint rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct ib_event ev; 9162306a36Sopenharmony_ci int full; 9262306a36Sopenharmony_ci void *addr; 9362306a36Sopenharmony_ci unsigned long flags; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci spin_lock_irqsave(&cq->cq_lock, flags); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci full = queue_full(cq->queue, QUEUE_TYPE_TO_CLIENT); 9862306a36Sopenharmony_ci if (unlikely(full)) { 9962306a36Sopenharmony_ci rxe_err_cq(cq, "queue full"); 10062306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, flags); 10162306a36Sopenharmony_ci if (cq->ibcq.event_handler) { 10262306a36Sopenharmony_ci ev.device = cq->ibcq.device; 10362306a36Sopenharmony_ci ev.element.cq = &cq->ibcq; 10462306a36Sopenharmony_ci ev.event = IB_EVENT_CQ_ERR; 10562306a36Sopenharmony_ci cq->ibcq.event_handler(&ev, cq->ibcq.cq_context); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return -EBUSY; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci addr = queue_producer_addr(cq->queue, QUEUE_TYPE_TO_CLIENT); 11262306a36Sopenharmony_ci memcpy(addr, cqe, sizeof(*cqe)); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci queue_advance_producer(cq->queue, QUEUE_TYPE_TO_CLIENT); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if ((cq->notify & IB_CQ_NEXT_COMP) || 11762306a36Sopenharmony_ci (cq->notify & IB_CQ_SOLICITED && solicited)) { 11862306a36Sopenharmony_ci cq->notify = 0; 11962306a36Sopenharmony_ci cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci spin_unlock_irqrestore(&cq->cq_lock, flags); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_civoid rxe_cq_cleanup(struct rxe_pool_elem *elem) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct rxe_cq *cq = container_of(elem, typeof(*cq), elem); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (cq->queue) 13262306a36Sopenharmony_ci rxe_queue_cleanup(cq->queue); 13362306a36Sopenharmony_ci} 134