1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  23  */
  24 
  25 #include <sys/ib/ibtl/impl/ibtl.h>
  26 
  27 /*
  28  * ibtl_cq.c
  29  *      These routines implement (most of) the verbs related to
  30  *      Completion Queues.
  31  */
  32 
  33 /*
  34  * Globals
  35  */
  36 
  37 static char ibtf_cq[] = "ibtl_cq";
  38 
  39 /*
  40  * This file contains code for the  TI CQ calls
  41  */
  42 
  43 /*
  44  * ibt_alloc_cq_sched() - Reserve CQ scheduling class resources
  45  *
  46  *      chan        - IBT Channel Handle.
  47  *      load        - Expected CQ load in class, 0 = unspecified
  48  *      sched_hdl_p - Returned scheduling handle.
  49  */
  50 ibt_status_t
  51 ibt_alloc_cq_sched(ibt_hca_hdl_t hca_hdl, ibt_cq_sched_attr_t *attr,
  52     ibt_sched_hdl_t *sched_hdl_p)
  53 {
  54         IBTF_DPRINTF_L3(ibtf_cq, "ibt_alloc_cq_sched(%p, %p, %p)",
  55             hca_hdl, attr, sched_hdl_p);
  56 
  57         return (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_cq_sched(
  58             IBTL_HCA2CIHCA(hca_hdl), attr, sched_hdl_p));
  59 }
  60 
  61 
  62 /*
  63  * ibt_free_cq_sched() - Free CQ scheduling class resources
  64  *
  65  *      chan      - IBT Channel Handle.
  66  *      sched_hdl - Scheduling handle returned from ibt_alloc_cq_sched.
  67  *      load      - CQ load being removed.
  68  */
  69 ibt_status_t
  70 ibt_free_cq_sched(ibt_hca_hdl_t hca_hdl, ibt_sched_hdl_t sched_hdl)
  71 {
  72         IBTF_DPRINTF_L3(ibtf_cq, "ibt_free_cq_sched(%p, %p)",
  73             hca_hdl, sched_hdl);
  74 
  75         return (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_free_cq_sched(
  76             IBTL_HCA2CIHCA(hca_hdl), sched_hdl));
  77 }
  78 
  79 
  80 /*
  81  *
  82  * ibt_alloc_cq() - Allocate a completion queue
  83  */
  84 ibt_status_t
  85 ibt_alloc_cq(ibt_hca_hdl_t hca_hdl, ibt_cq_attr_t *cq_attr,
  86     ibt_cq_hdl_t *ibt_cq_p, uint32_t *real_size)
  87 {
  88         ibt_status_t            status;
  89         ibt_cq_hdl_t            ibt_cq;
  90 
  91         IBTF_DPRINTF_L3(ibtf_cq, "ibt_alloc_cq(%p, %p)",
  92             hca_hdl, cq_attr);
  93 
  94 
  95         ibt_cq = kmem_zalloc(sizeof (struct ibtl_cq_s), KM_SLEEP);
  96         *ibt_cq_p = ibt_cq;
  97 
  98         /*
  99          * Set the following values before creating CI CQ, to avoid race
 100          * conditions on async callback.
 101          */
 102         ibt_cq->cq_hca = hca_hdl;
 103 
 104         ibtl_qp_flow_control_enter();
 105         status = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_cq(
 106             IBTL_HCA2CIHCA(hca_hdl), ibt_cq, cq_attr, &ibt_cq->cq_ibc_cq_hdl,
 107             real_size);
 108         ibtl_qp_flow_control_exit();
 109 
 110         if (status != IBT_SUCCESS) {
 111                 IBTF_DPRINTF_L2(ibtf_cq, "ibt_alloc_cq: "
 112                     "CI CQ handle allocation failed: status = %d", status);
 113                 kmem_free(ibt_cq, sizeof (struct ibtl_cq_s));
 114                 *ibt_cq_p = NULL;
 115                 return (status);
 116         }
 117 
 118         if (cq_attr->cq_flags & IBT_CQ_HANDLER_IN_THREAD) {
 119                 ibt_cq->cq_in_thread = 1;
 120                 /* We may want additional CQ threads now. */
 121                 ibtl_another_cq_handler_in_thread();
 122         }
 123 
 124         mutex_init(&ibt_cq->cq_mutex, NULL, MUTEX_DEFAULT, NULL);
 125 
 126         /* Update the cq resource count */
 127         atomic_inc_32(&hca_hdl->ha_cq_cnt);
 128 
 129         return (IBT_SUCCESS);
 130 }
 131 
 132 
 133 /*
 134  * ibt_free_cq() - Free a completion queue
 135  *
 136  */
 137 ibt_status_t
 138 ibt_free_cq(ibt_cq_hdl_t ibt_cq)
 139 {
 140         ibt_status_t    status;
 141         ibtl_hca_t      *ibt_hca = ibt_cq->cq_hca;
 142 
 143         IBTF_DPRINTF_L3(ibtf_cq, "ibt_free_cq(%p)", ibt_cq);
 144 
 145         ibtl_free_cq_check(ibt_cq);
 146 
 147         status = ((IBTL_CQ2CIHCAOPS_P(ibt_cq))->ibc_free_cq)
 148             (IBTL_CQ2CIHCA(ibt_cq), ibt_cq->cq_ibc_cq_hdl);
 149 
 150         if (status != IBT_SUCCESS) {
 151                 IBTF_DPRINTF_L2(ibtf_cq, "ibt_free_cq: "
 152                     "CI CQ handle de-allocation failed: status = %d", status);
 153                 return (status);
 154         }
 155 
 156         /* mutex_destroy(&ibt_cq->cq_mutex); */
 157         ibtl_free_cq_async_check(ibt_cq);
 158 
 159         /* Update the cq resource count */
 160         atomic_dec_32(&ibt_hca->ha_cq_cnt);
 161 
 162         return (status);
 163 }
 164 
 165 
 166 /*
 167  * ibt_query_cq() - Returns the size of the cq
 168  */
 169 ibt_status_t
 170 ibt_query_cq(ibt_cq_hdl_t ibt_cq, uint32_t *entries_p, uint_t *count_p,
 171     uint_t *usec_p, ibt_cq_handler_id_t *hid_p)
 172 {
 173         IBTF_DPRINTF_L3(ibtf_cq, "ibt_query_cq(%p)", ibt_cq);
 174 
 175         return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_query_cq(IBTL_CQ2CIHCA(ibt_cq),
 176             ibt_cq->cq_ibc_cq_hdl, entries_p, count_p, usec_p, hid_p));
 177 }
 178 
 179 
 180 /*
 181  *  ibt_resize_cq() - Change the size of a cq.
 182  */
 183 ibt_status_t
 184 ibt_resize_cq(ibt_cq_hdl_t ibt_cq, uint32_t new_sz, uint32_t *real_sz)
 185 {
 186         IBTF_DPRINTF_L3(ibtf_cq, "ibt_resize_cq(%p, %d)", ibt_cq, new_sz);
 187 
 188         return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_resize_cq(IBTL_CQ2CIHCA(ibt_cq),
 189             ibt_cq->cq_ibc_cq_hdl, new_sz, real_sz));
 190 }
 191 
 192 ibt_status_t
 193 ibt_modify_cq(ibt_cq_hdl_t ibt_cq, uint_t count, uint_t usec,
 194     ibt_cq_handler_id_t hid)
 195 {
 196         IBTF_DPRINTF_L3(ibtf_cq, "ibt_modify_cq(%p, %d, %d, %d)", ibt_cq, count,
 197             usec, hid);
 198 
 199         return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_modify_cq(IBTL_CQ2CIHCA(ibt_cq),
 200             ibt_cq->cq_ibc_cq_hdl, count, usec, hid));
 201 }
 202 
 203 
 204 /*
 205  * ibt_poll_cq()
 206  *      Poll the specified CQ for a work request (WR) completion. If a CQ
 207  *      contains a completed WR, the completed WR at the head of the CQ is
 208  *      returned.
 209  *
 210  *      ibt_cq                  The CQ handle.
 211  *
 212  *      work_completions        An array of work completions.
 213  *
 214  *      num_wc                  Size of the Work completion array. The
 215  *                              requested number of completions.
 216  *
 217  *      num_polled              The actual number of completions returned.
 218  *
 219  */
 220 ibt_status_t
 221 ibt_poll_cq(ibt_cq_hdl_t ibt_cq, ibt_wc_t *work_completions, uint_t num_wc,
 222     uint_t *num_polled)
 223 {
 224         IBTF_DPRINTF_L4(ibtf_cq, "ibt_poll_cq(%p)", ibt_cq);
 225 
 226         return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_poll_cq(IBTL_CQ2CIHCA(ibt_cq),
 227             ibt_cq->cq_ibc_cq_hdl, work_completions, num_wc, num_polled));
 228 }
 229 
 230 /*
 231  * ibt_set_cq_private - Sets the private data on a given CQ
 232  *
 233  *      ibt_cq          The ibt_cq_hdl_t of the allocated CQ.
 234  *      clnt_private    The client private data.
 235  */
 236 void
 237 ibt_set_cq_private(ibt_cq_hdl_t ibt_cq, void *clnt_private)
 238 {
 239         ibt_cq->cq_clnt_private = clnt_private;
 240 }
 241 
 242 
 243 /*
 244  * ibt_get_cq_private - Retrieves the private data for a given CQ
 245  *
 246  *      ibt_cq          The ibt_cq_hdl_t of the allocated CQ.
 247  */
 248 void *
 249 ibt_get_cq_private(ibt_cq_hdl_t ibt_cq)
 250 {
 251         return (ibt_cq->cq_clnt_private);
 252 }
 253 
 254 /*
 255  * ibt_query_cq_handler_id - Retrieves the attributes of a cq_handler_id.
 256  */
 257 ibt_status_t
 258 ibt_query_cq_handler_id(ibt_hca_hdl_t hca_hdl,
 259     ibt_cq_handler_id_t hid, ibt_cq_handler_attr_t *attrs)
 260 {
 261         IBTF_DPRINTF_L3(ibtf_cq, "ibt_query_cq_handler(%p, %d, %p)",
 262             hca_hdl, hid, attrs);
 263 
 264         return (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_query_cq_handler_id(
 265             IBTL_HCA2CIHCA(hca_hdl), hid, attrs));
 266 }