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         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibt_cq->cq_in_thread))
  99         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibt_cq->cq_ibc_cq_hdl))
 100         _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibt_cq->cq_hca))
 101         /*
 102          * Set the following values before creating CI CQ, to avoid race
 103          * conditions on async callback.
 104          */
 105         ibt_cq->cq_hca = hca_hdl;
 106 
 107         ibtl_qp_flow_control_enter();
 108         status = IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_alloc_cq(
 109             IBTL_HCA2CIHCA(hca_hdl), ibt_cq, cq_attr, &ibt_cq->cq_ibc_cq_hdl,
 110             real_size);
 111         ibtl_qp_flow_control_exit();
 112 
 113         if (status != IBT_SUCCESS) {
 114                 IBTF_DPRINTF_L2(ibtf_cq, "ibt_alloc_cq: "
 115                     "CI CQ handle allocation failed: status = %d", status);
 116                 kmem_free(ibt_cq, sizeof (struct ibtl_cq_s));
 117                 *ibt_cq_p = NULL;
 118                 return (status);
 119         }
 120 
 121         if (cq_attr->cq_flags & IBT_CQ_HANDLER_IN_THREAD) {
 122                 ibt_cq->cq_in_thread = 1;
 123                 /* We may want additional CQ threads now. */
 124                 ibtl_another_cq_handler_in_thread();
 125         }
 126         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibt_cq->cq_in_thread))
 127         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibt_cq->cq_ibc_cq_hdl))
 128         _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibt_cq->cq_hca))
 129 
 130         mutex_init(&ibt_cq->cq_mutex, NULL, MUTEX_DEFAULT, NULL);
 131 
 132         /* Update the cq resource count */
 133         atomic_inc_32(&hca_hdl->ha_cq_cnt);
 134 
 135         return (IBT_SUCCESS);
 136 }
 137 
 138 
 139 /*
 140  * ibt_free_cq() - Free a completion queue
 141  *
 142  */
 143 ibt_status_t
 144 ibt_free_cq(ibt_cq_hdl_t ibt_cq)
 145 {
 146         ibt_status_t    status;
 147         ibtl_hca_t      *ibt_hca = ibt_cq->cq_hca;
 148 
 149         IBTF_DPRINTF_L3(ibtf_cq, "ibt_free_cq(%p)", ibt_cq);
 150 
 151         ibtl_free_cq_check(ibt_cq);
 152 
 153         status = ((IBTL_CQ2CIHCAOPS_P(ibt_cq))->ibc_free_cq)
 154             (IBTL_CQ2CIHCA(ibt_cq), ibt_cq->cq_ibc_cq_hdl);
 155 
 156         if (status != IBT_SUCCESS) {
 157                 IBTF_DPRINTF_L2(ibtf_cq, "ibt_free_cq: "
 158                     "CI CQ handle de-allocation failed: status = %d", status);
 159                 return (status);
 160         }
 161 
 162         /* mutex_destroy(&ibt_cq->cq_mutex); */
 163         ibtl_free_cq_async_check(ibt_cq);
 164 
 165         /* Update the cq resource count */
 166         atomic_dec_32(&ibt_hca->ha_cq_cnt);
 167 
 168         return (status);
 169 }
 170 
 171 
 172 /*
 173  * ibt_query_cq() - Returns the size of the cq
 174  */
 175 ibt_status_t
 176 ibt_query_cq(ibt_cq_hdl_t ibt_cq, uint32_t *entries_p, uint_t *count_p,
 177     uint_t *usec_p, ibt_cq_handler_id_t *hid_p)
 178 {
 179         IBTF_DPRINTF_L3(ibtf_cq, "ibt_query_cq(%p)", ibt_cq);
 180 
 181         return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_query_cq(IBTL_CQ2CIHCA(ibt_cq),
 182             ibt_cq->cq_ibc_cq_hdl, entries_p, count_p, usec_p, hid_p));
 183 }
 184 
 185 
 186 /*
 187  *  ibt_resize_cq() - Change the size of a cq.
 188  */
 189 ibt_status_t
 190 ibt_resize_cq(ibt_cq_hdl_t ibt_cq, uint32_t new_sz, uint32_t *real_sz)
 191 {
 192         IBTF_DPRINTF_L3(ibtf_cq, "ibt_resize_cq(%p, %d)", ibt_cq, new_sz);
 193 
 194         return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_resize_cq(IBTL_CQ2CIHCA(ibt_cq),
 195             ibt_cq->cq_ibc_cq_hdl, new_sz, real_sz));
 196 }
 197 
 198 ibt_status_t
 199 ibt_modify_cq(ibt_cq_hdl_t ibt_cq, uint_t count, uint_t usec,
 200     ibt_cq_handler_id_t hid)
 201 {
 202         IBTF_DPRINTF_L3(ibtf_cq, "ibt_modify_cq(%p, %d, %d, %d)", ibt_cq, count,
 203             usec, hid);
 204 
 205         return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_modify_cq(IBTL_CQ2CIHCA(ibt_cq),
 206             ibt_cq->cq_ibc_cq_hdl, count, usec, hid));
 207 }
 208 
 209 
 210 /*
 211  * ibt_poll_cq()
 212  *      Poll the specified CQ for a work request (WR) completion. If a CQ
 213  *      contains a completed WR, the completed WR at the head of the CQ is
 214  *      returned.
 215  *
 216  *      ibt_cq                  The CQ handle.
 217  *
 218  *      work_completions        An array of work completions.
 219  *
 220  *      num_wc                  Size of the Work completion array. The
 221  *                              requested number of completions.
 222  *
 223  *      num_polled              The actual number of completions returned.
 224  *
 225  */
 226 ibt_status_t
 227 ibt_poll_cq(ibt_cq_hdl_t ibt_cq, ibt_wc_t *work_completions, uint_t num_wc,
 228     uint_t *num_polled)
 229 {
 230         IBTF_DPRINTF_L4(ibtf_cq, "ibt_poll_cq(%p)", ibt_cq);
 231 
 232         return (IBTL_CQ2CIHCAOPS_P(ibt_cq)->ibc_poll_cq(IBTL_CQ2CIHCA(ibt_cq),
 233             ibt_cq->cq_ibc_cq_hdl, work_completions, num_wc, num_polled));
 234 }
 235 
 236 _NOTE(SCHEME_PROTECTS_DATA("client managed", ibtl_cq_s::cq_clnt_private))
 237 
 238 /*
 239  * ibt_set_cq_private - Sets the private data on a given CQ
 240  *
 241  *      ibt_cq          The ibt_cq_hdl_t of the allocated CQ.
 242  *      clnt_private    The client private data.
 243  */
 244 void
 245 ibt_set_cq_private(ibt_cq_hdl_t ibt_cq, void *clnt_private)
 246 {
 247         ibt_cq->cq_clnt_private = clnt_private;
 248 }
 249 
 250 
 251 /*
 252  * ibt_get_cq_private - Retrieves the private data for a given CQ
 253  *
 254  *      ibt_cq          The ibt_cq_hdl_t of the allocated CQ.
 255  */
 256 void *
 257 ibt_get_cq_private(ibt_cq_hdl_t ibt_cq)
 258 {
 259         return (ibt_cq->cq_clnt_private);
 260 }
 261 
 262 /*
 263  * ibt_query_cq_handler_id - Retrieves the attributes of a cq_handler_id.
 264  */
 265 ibt_status_t
 266 ibt_query_cq_handler_id(ibt_hca_hdl_t hca_hdl,
 267     ibt_cq_handler_id_t hid, ibt_cq_handler_attr_t *attrs)
 268 {
 269         IBTF_DPRINTF_L3(ibtf_cq, "ibt_query_cq_handler(%p, %d, %p)",
 270             hca_hdl, hid, attrs);
 271 
 272         return (IBTL_HCA2CIHCAOPS_P(hca_hdl)->ibc_query_cq_handler_id(
 273             IBTL_HCA2CIHCA(hca_hdl), hid, attrs));
 274 }